一、類載入過程 執行時機:編譯程式——>執行程式(JVM啟動、程式運行),類載入發生在程式運行期間 各個階段:分為載入階段、連接階段(驗證、準備、解析)、初始化、使用、卸載 執行順序:大體是按以上階段依次執行,但相互間有交叉 載入——>驗證(文件格式)——>繼續載入——>解析——>驗證(元數據、位元組 ...
一、類載入過程 執行時機:編譯程式——>執行程式(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類隨著它的類載入器一起具備了一種優先順序的層次關係
數組類(組件類型為引用類型,如Person[][])、非數組類/介面: 遞歸載入組件類型,每次去掉一個維度
2.載入“類/介面”的策略:
非數組類/介面、數組類(組件類型為基本類型,如int[][]):
載入生成代表這個類的java.lang.Class對象後,將在類載入器的“類名稱空間”上標識為“已載入”(因為前面已經討論了,同一Class文件對應同一個類載入器才確定生成的是同一個Class對象)
連接階段:
驗證——文件格式、元數據、位元組碼
準備——在方法區為類變數分配記憶體並初始化
例子 編譯時期 (類載入時)驗證階段—準備時期
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.主動引用、被動引用 被動引用——會發生類載入,但不會初始化 ——例子:略