程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> 讀《深入理解Java虛擬機》有感——第二部分:虛擬機類加載機制,

讀《深入理解Java虛擬機》有感——第二部分:虛擬機類加載機制,

編輯:JAVA綜合教程

讀《深入理解Java虛擬機》有感——第二部分:虛擬機類加載機制,


一、類加載過程       執行時機:編譯程序——>執行程序(JVM啟動、程序運行),類加載發生在程序運行期間
      各個階段:分為加載階段、連接階段(驗證、准備、解析)、初始化、使用、卸載
      執行順序:大體是按以上階段依次執行,但相互間有交叉                        加載——>驗證(文件格式)——>繼續加載——>解析——>驗證(元數據、字節碼)——>准備——>初始化
      參與角色:Class文件、Java虛擬機、類加載器                          /**HotSpot的Bootstrap ClassLoader(啟動類加載器)是位於虛擬機內部(由C++實現),其它類加載器外置於JVM(由Java實現)*/   二、說明—各個階段       加載階段:            普通類/接口、 數組類(組件類型為基本類型,如int[][]):獲取、轉化、創建、觸發                    獲取——類加載器加載Class文件(指定路徑+文件名 ——>確定“全限定名稱”——>拿到Class文件(與平台無關的二進制字節流))                    轉化——字節碼以一定轉化成格式,存放在方法區                    創建——方法區中生成一個代表這個類的java.lang.Class對象                    觸發——加載的同時,會觸發父類、關聯引用類的加載                                              class A extends B————>Class<B>                                private Class<Person> class————>Class<Person>                                 Class c =Person.getClass(); ————>Class<Person>                                                                     
1.關於“類加載器”和“生成的這個Class對象”:
1)類加載器
Bootstrap Loader(啟動類加載器)、Extended Loader(標准擴展類加載器ExtClassLoader)、AppClass Loader(系統類加載器/應用程序類加載器AppClassLoader)
啟動類加載器:
目的:加載java_home\lib目錄下的字節碼文件(如:rt.jar,含有java.lang.Object等基本類) 具體有哪些文件及加載順序?
方式:加載System.getProperty("sun.boot.class.path")所指定的路徑或jar,在使用Java運行程序時,也可以指定其搜索路徑,例如:java -Djava.ext.dirs=d:\projects\testproj\classes HelloWorld 參考:http://www.cnblogs.com/ITtangtang/p/3978102.htm
               標准擴展類加載器:
目的:加載java_home\lib\ext目錄下的字節碼文件
                         方式:加載System.getProperty("java.ext.dirs")所指定的路徑或jar。在使用Java運行程序時,也可以指定其搜索路徑,例如:java -Djava.ext.dirs=d:\projects\testproj\classes HelloWorld
結果:<實現類>sun.misc.Luncher@ExtClassLoader————————<繼承關系>ClassLoader>URLClassLoader>AppClassLoader

               應用程序類加載器:
方式:加載System.getProperty("java.class.path")所指定的路徑或jar。在使用Java運行程序時,也可以加上-cp來覆蓋原有的Classpath設置,例如: java -cp ./lavasoft/classesHelloWorld
結果:<實現類>sun.misc.Luncher@AppClassLoader————————<繼承關系>ClassLoader>URLClassLoader>AppClassLoader

自定義類加載器:
方式:1)繼承java.lang.ClassLoader並重寫loadClass方法;2)繼承java.lang.ClassLoader並重寫findClass方法/**JDK1.2後推薦,原因見下方紅色部分*/;
相關:
 1 <一>java.lang.Object
 2 1.getClass()
 3 public final native Class<?> getClass();    //拿到運行時的Class對象【通過本地方法】
 4 /**
 5  *例子:class-Test>main> 
 6  *                    Class c =Person.getClass();
 7  */
 8      /**
 9        *實現:  
10        *1)虛擬機啟動
11        *2)虛擬機類加載——Test.class————加載階段:方法區>外部接口>new java.lang.Class  //Class<?>     
12        *3)虛擬機類加載——java.lang.Object————【Test加載階段】觸發
13        *3)虛擬機類加載——Person.class    ————【Test加載階段】觸發
14        *4)應用程序啟動
15        *5)調用java.lang.ClassLoader>xxx1()、xxx2().....——返回運行時<Person>Class對象
16        */
17 
18 
19 <二>java。lang.ClassLoader
20       1.loadClass(String name, boolean resolve)  /**加載指定名稱(包括包名)的二進制類型,同時指定是否解析*/
21         loadClass(String name)   
22     protected Class<?> findClass(String name) throws ClassNotFoundException {   //空方法
23         throw new ClassNotFoundException(name);
24     }
25     protected Class<?> loadClass(String name, boolean resolve)    //拿到類加載器【通過本地方法】
26         throws ClassNotFoundException
27     {
28         synchronized (getClassLoadingLock(name)) {
29             // First, check if the class has already been loaded
30             Class c = findLoadedClass(name);
31             if (c == null) {
32                 long t0 = System.nanoTime();
33                 try {
34                     if (parent != null) {
35                         c = parent.loadClass(name, false);
36                     } else {
37                         c = findBootstrapClassOrNull(name);
38                     }
39                 } catch (ClassNotFoundException e) {
40                     // ClassNotFoundException thrown if class not found
41                     // from the non-null parent class loader
42                 }
43 
44                 if (c == null) {
45                     // If still not found, then invoke findClass in order
46                     // to find the class.
47                     long t1 = System.nanoTime();
48                     c = findClass(name);
49 
50                     // this is the defining class loader; record the stats
51                     sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
52                     sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
53                     sun.misc.PerfCounter.getFindClasses().increment();
54                 }
55             }
56             if (resolve) {
57                 resolveClass(c);
58             }
59             return c;
60         }
61     }
62     
63     
64     
65     
66 <三>java.lang.Class   
67      1.getClassLoader()
68 /**例子:class-Test>main>
69   *                    Object o =new Object();
70   *                       System.out.println(o.getClass().getClassLoader());
71                                                                    結果>java.lang.NullPointerException   
72   */                          
73      /**
74       *Returns the class loader for the class.  
75       *This method will return null in such implementations if this class was loaded by the bootstrap class loader. 
76       *如果沒有指定classLoader就默認返回bootstrap classLoader(啟動類加載器),因為這個bootstrap classLoader
77       *用戶拿不到實例,所以返回null表示返回的是bootstrap classLoader     
78       */
79 native ClassLoader getClassLoader0();      //拿到類加載器【通過本地方法】
80 public ClassLoader getClassLoader() {
81         ClassLoader cl = getClassLoader0();
82         if (cl == null)
83             return null;
84         SecurityManager sm = System.getSecurityManager();
85         if (sm != null) {
86             ClassLoader.checkClassLoaderPermission(cl, Reflection.getCallerClass());
87         }
88         return cl;
89     }
2.指定類加載器加載類
Class.forName(name, initialize, loader)

 

       2)與“生成的Class對象”關系
同一Class文件只有被同一類加載器加載,才能判斷為相等————>相等的意義在於:1)不相等,會生成多個Class對象;相等,只會生成一個Class對象
2) 只有同一個Class對象,equals()、isAssignabaleFrom()、instanceof、isInstance()返回結果才相同;
       3)雙親委派模型 

關系?
上一級持有下一級的一個引用,屬於 has A關系
分工?(為什麼叫雙親委派)
一個類加載器收到了類加載的請求,它首先不會自己去嘗試加載這個類,而是把這個請求委派給上一層的類加載器去完成。只有當上級加載器在搜索范圍找不到所需類,無法完成這個加載請求時,下級加載器才會嘗試自己去加載
好處?
Java類隨著它的類加載器一起具備了一種優先級的層次關系



2.加載“類/接口”的策略:
非數組類/接口、數組類(組件類型為基本類型,如int[][]):
加載生成代表這個類的java.lang.Class對象後,將在類加載器的“類名稱空間”上標識為“已加載”(因為前面已經討論了,同一Class文件對應同一個類加載器才確定生成的是同一個Class對象)
           數組類(組件類型為引用類型,如Person[][])、非數組類/接口:                  遞歸加載組件類型,每次去掉一個維度


 

      連接階段:

            驗證——文件格式、元數據、字節碼

            准備——在方法區為類變量分配內存並初始化

                               例子                     編譯時期                                                             (類加載時)驗證階段—准備時期

                static int i =20;             產生constantValue屬性,但不會存入常量20                       常規方式進行准備:初始化、分配內存

                             結果—————>        無                                                                                    0                                                                                            

         final static int i =20;             產生constantValue屬性,並存20到constantValue               從對應constantValue取出來初始化

                             結果—————>       20                                                                                   20

            解析——將運行時常量池的符號引用替換為直接引用(指向內存目標的句柄),這一過程又叫“靜態綁定/靜態連接”

 

 

 

      初始化階段:(動態綁定/動態連接)               1. 執行時機——主動引用(new、反射、父類、執行主類包含main方法、調用靜態方法                   *new                            ——執行父類的<clinit>()、執行本類的<clinit>()、執行父類的<client>、執行本類的<client>
 1 //例子(筆試常考題目)
 2 public class Father {
 3 
 4 private static int i =20;
 5 static{
 6     System.out.println("Father;(類構造器-before)"+i);
 7     i =50;
 8     System.out.println("Father;(類構造器-after)"+i);
 9 }
10 public Father() {
11     System.out.println("Father:(實例構造器)"+i);13 }
14 
15 }
16 
17 
18 
19 public class Son extends Father{
20 
21     private static int i =20;
22     static{
23         System.out.println("Son;(類構造器-before)"+i);
24         i =50;
25         System.out.println("Son;(類構造器-after)"+i);
26     }
27     public Son() {
28         System.out.println("Son:(實例構造器)"+i);        30     }
31 }
32 
33 
34 
35 public class Main {
36 
37     public static void main(String[] args) {
38         new Son();
39 
40     }
41 
42 }
43 
44 //輸出結果:
45         /**
46            *Father;(類構造器-before)20
47            *Father;(類構造器-after)50
48            *Son;(類構造器-before)20
49            *Son;(類構造器-after)50
50            *Father:(實例構造器)50
51            *Son:(實例構造器)50
52            */

 

                   2.主動引用、被動引用                              被動引用——會發生類加載,但不會初始化                                          ——例子:略

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved