探究java-JVM的五步(三步)类加载机制(包含类加载过程的一些代码书写,如类加载代码)
前言:
寫了不少java代碼,以前一直都是關心java程序跑起來后的情況步驟,今天我們就來探究一下:
在java程序還是一個個存在于靜態.class文件中的類(也可以是任何被JVM認可的文件,但本質還是要的到類)的時候,JVM是在怎么將它們變成一個個存在于內存的對象的。
為此,JVM專門有一個類加載機制,用于處理.class文件加載到內存這個過程。
正文:
JVM類加載機制分為5個步驟:
1.加載
2.驗證
3.準備
4.解析
5.初始化
分別簡單介紹一下他們的概念,
1.加載
通常使用顯式的加載Class.forName()
隱性加載:new對象時加載{在jvm開啟后通過文件加載}
就是JVM通過一個文件得到一個類并在內存中進行生成java.lang.Class對象,一定在堆上。
既是通過文件加載到內存
注意,對于文件我們有一定的要求:
首先就是要滿足JVM指定的規范,既是.class文件遵循的規范,
文件不一定是.class文件,JVM還能在jar包,war包一類的文件中獲取到加載類需要的class信息,還有jsp文件也能通過動態代理產生一個可識別的class。
我們需要知道類加載器有三種:
啟動類加載器(jdk的bin目錄)
擴展類加載器(jdk的lib\ext目錄)
應用程序類加載器(自定義的加載器,繼承java.lang.ClassLoader)
它們的關系是雙親委派,什么是雙親委派,就是當自己需要完成一個任務時不先自己考慮能否處理,先向上一代拋出任務,直到頂層(既是啟動類加載器),然后再判斷每個層能否處理這個任務**(在自己路徑下能否找到類)**,不能則向下拋,直到能夠處理為止
我們舉個栗子,java.lang.Object對象位于rt.jar,是jdk\bin目錄下的,該啟動類加載器管理,我們都知道不管哪個對象都可以認為是Object對象。
那是因為不管哪一級的加載器想要加載Object對象
在雙親委派模式下都會被委托給啟動類加載器,始終能得到同一個Object對象。
好了,現在我們在不重寫的情況下實現一個自己的類加載器(此處被封裝為一個方法,功能類似于Class.forName())
首先準備一個.class文件,源碼功能如下:
然后封裝一個方法(加載到類并返回):
/*** @Description: 手動加載一個.class文件(以test.PrintJVMLoad為例,其他的不做實驗)* ;類加載器* @Param:* @Return: 加載到的類* @Date: 2020/6/11 0011*/public static Object loadClassByFile(String Filename){//class文件位置String constUrl="\\target\\classes\\com\\j\\test";Object object=null;try {//URLURL url = new URL("file:\\"+System.getProperty("user.dir")+constUrl);//得到加載器URLClassLoader loader=new URLClassLoader(new URL[]{url});//得到對應class對象Class c = loader.loadClass(Filename);//得到對象object = c.newInstance();} catch (Exception e) {e.printStackTrace();}return object;}然后檢驗是否加載成功:
//測試類加載,一定是完整的java-package路徑Object o=JVMClassLoad.loadClassByFile("com.j.test.PrintJVMLoad");if (o!=null){((PrintJVMLoad)o).loadTest();}else {System.out.println("類加載失敗");}運行結果如下:
方法被成功調用,成功了
2.驗證
驗證,準備,解析三步合稱鏈接。
驗證是為了是的.class文件是被JVM認可的,不危害JVM的。
3.準備
通常是為了將定義的類成員變量(靜態的,在方法區)進行一個賦值或者初始化。
例如:
在準備階段,其僅僅會將a設為0,而不是80,80這個賦值操作將在初始化時放在類構造器()執行
public static final int a=80此時會直接將a賦值為80,
因為此時在編譯時變量a會產生一個ConstantValue屬性,是直接賦值的依據。
4.解析
是JVM通過常量池將符號引用轉為直接引用的過程
符號引用不一定存在于內存中(符號引用是一種.class文件規范規定),但直接引用是一個指針,一定指向了一個具體地址,一定在內存中。
這么理解就容易了
就是將.class文件中的規范翻譯成JVM認得的類構造規范(常量池的那些常量)
既是—翻譯
5.初始化
此時以執行類構造器方法()為主。
此時在類構造器方法中會執行類似對類成員賦值(準備階段的傳遞的任務),靜態的代碼。
類構造器遵循繼承原則,在父類完成執行后,才執行子類。
一般無靜態模塊(任何靜態的變量,代碼塊)的方法可不執行類構造器方法。
顯式的調用也不會。
//
JVM中的類加載機制大抵是這樣了。
感謝耐心的閱讀,希望能幫到你。
//
總結
以上是生活随笔為你收集整理的探究java-JVM的五步(三步)类加载机制(包含类加载过程的一些代码书写,如类加载代码)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: idea-jvm参数设置(有注释)
- 下一篇: java-List集合的源码分析(数据结