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.主動引用、被動引用 被動引用——會發生類加載,但不會初始化 ——例子:略