做app布局參考哪個網(wǎng)站紹興seo排名外包
目錄
1.類文件結構
?2.類加載器?
3.類加載的三個階段
? ? ? ? 3.1加載
? ? ? ? 3.2鏈接?
? ? ? ? ? ? ? ? 3.2.1驗證
????????????????3.2.2準備階段
? ? ? ? ????????3.2.3解析階段
? ? ? ? 3.3初始化
4.拓展:反射
????????4.1獲取類對象
????????4.2創(chuàng)建實例
? ? ? ? 4.3獲取方法
?? ? ? ?4.4方法調(diào)用
1.類文件結構
?2.類加載器?
? ? ? ? 類加載器用來將類文件的二進制字節(jié)碼加載到JVM的方法區(qū)中。有四種類加載器:
????????連接數(shù)據(jù)庫驅(qū)動調(diào)用的類加載器:在連接數(shù)據(jù)庫時會調(diào)用DriverManager類進行驅(qū)動,而DriverManager是核心類,所以會使用到啟動類加載器;但數(shù)據(jù)庫連接的驅(qū)動包并不在核心類庫中,所以DriverManager類中有一個loadInitialDrivers()方法,內(nèi)部使用了兩種方式加載驅(qū)動:
? ? ? ? ? 第一種是SPI機制加載驅(qū)動,約定是在jar包中添加一個META-INF/services目錄,在其中添加一個配置文件,文件的名稱就是接口的全限定名稱,數(shù)據(jù)庫連接驅(qū)動就是java.sql.Driver,文件內(nèi)容就是接口的實現(xiàn)類 ;通過ServiceLoader.load()方法根據(jù)約定的路徑找到實現(xiàn)類;這個load方法的內(nèi)部調(diào)用的是線程上下文類加載器,由于在創(chuàng)建線程時默認分配的是應用類加載器,所以這種機制實際上調(diào)用的是應用類加載器。第二種是使用系統(tǒng)變量jdbc.drivers定義的驅(qū)動類的類名加載驅(qū)動,調(diào)用Class.forName()方法加載和初始化驅(qū)動類,使用的是系統(tǒng)類加載器,也就是應用類加載器。
? ? ? ? 數(shù)據(jù)庫連接驅(qū)動是先調(diào)用的系統(tǒng)類加載器再調(diào)用的應用類加載器,所以在某些情況下會打破雙親委派機制。
3.類加載的三個階段
? ? ? ? 類加載分為三個階段:加載、鏈接、初始化。鏈接又分為三個階段:驗證、準備、解析。
? ? ? ? 3.1加載
????????
? ? ? ? 要注意的是,一個類的.class文件加載到方法區(qū)后變成了C++的instanceKlass文件,這個文件中包含了這個類的各種信息,然后再在堆中生成一個Class類型的對象(區(qū)分class,class是定義一個類用的;區(qū)分.class文件,這是編譯生成的一個類的二進制字節(jié)碼,還沒有被加載),因為java不能直接訪問方法區(qū)的instanceKlass,所以需要這個Class副本來供我們使用,通過反射拿到的一個類的Class對象就是這么來的,這也就是為什么這個Class對象被叫做類鏡像了。
? ? ? ? 3.2鏈接?
? ? ? ? ? ? ? ? 3.2.1驗證
????????驗證這個類轉(zhuǎn)換的字節(jié)碼是否符合JVM規(guī)范,并進行安全性檢查,比如檢查字節(jié)碼中的魔數(shù)是否是Java文件的魔數(shù)。
????????????????3.2.2準備階段
????????給靜態(tài)變量分配空間,并設置默認值:
- 靜態(tài)變量在JDK7之前是放在instanceKlass的末尾也就是方法區(qū)中,而在JDK7之后則是放在了類鏡像末尾,也就是堆內(nèi)存中。
- 靜態(tài)變量的空間分配在準備階段完成,而賦值則是在初始化階段,但是final類型的靜態(tài)變量比較特殊:如果是final的基本類型或字符串類型的靜態(tài)變量,則分配空間和賦值都在準備階段完成,因為對于這些類型的變量而言final說明值不會改變,已經(jīng)確定了靜態(tài)變量的值,所以在準備階段會直接賦值;而如果是final的引用類型的靜態(tài)變量則賦值會放在初始化階段,因為new一個對象需要類先初始化完成后才能創(chuàng)建。
? ? ? ? ?????????3.2.3解析階段
????????將常量池的符號引用解析為直接引用。符號引用就是這個類雖然被加載了,但由于還沒有進行解析,也就不知道這個類在內(nèi)存中的位置,相當于只是一個符號;而直接引用就是經(jīng)過了解析之后,知道了其在內(nèi)存中的具體位置,就可以訪問這個類了。
? ? ? ? 3.3初始化
????????類的初始化是為了確保類的結構正確并且所有的數(shù)據(jù)都已初始化為預期的狀態(tài),只有在類的初始化完成后才能在系統(tǒng)中正常使用這個類及其方法和屬性。初始化過程主要包括給靜態(tài)變量賦值、靜態(tài)代碼塊的執(zhí)行等,只有首次主動使用時才會觸發(fā)初始化,初始化是懶惰的,且只進行一次。
????????初始化發(fā)生的時機:
- main方法所在的類會先進行初始化。
- 首次訪問這個類的靜態(tài)變量或靜態(tài)方法時。
- 子類進行初始化時,若父類還沒有初始化,則會先進行父類的初始化再進行子類的初始化。
- 當子類訪問父類的靜態(tài)變量時,只會觸發(fā)父類的初始化。
- 當執(zhí)行Class.forName方法時,會執(zhí)行類加載并默認進行初始化;當然也可以給參數(shù)initialize設置為false表示不執(zhí)行初始化。
- 通過new創(chuàng)建實例化對象時會觸發(fā)初始化。
????????以下情況不會觸發(fā)初始化:
- 訪問靜態(tài)常量時,因為靜態(tài)常量的空間分配和賦值均在鏈接時的準備階段完成。
- 使用類加載器的loadClass方法時,loadClass方法只進行加載階段。
- 訪問類對象的.class文件時不會觸發(fā)初始化,因為Class對象在class文件加載到方法區(qū)后就會生成,所以在加載階段時就已經(jīng)生成。
- 創(chuàng)建該類的數(shù)組不會觸發(fā)初始化,因為在JVM中會生成一個其他的類來表示數(shù)組類型,與原本的類無關,所以不會觸發(fā)原來的類的初始化。
4.拓展:反射
? ? ? ? 反射:通過使用類對象(即堆中的Class對象)來創(chuàng)建實例、調(diào)用方法等。? ?
????????4.1獲取類對象
Class c=類名.forName();
或
Class<?> c=類名.class;
或
Class<?> c=類名.getClass();
? ? ? ? 以下操作都建立在獲取了Class對象的基礎上
????????4.2創(chuàng)建實例
Object o=c.newInstance();
? ? ? ? 也可以通過指定的構造器來創(chuàng)建實例,比如使用String的構造器來創(chuàng)建實例:??
//先獲取String類的帶一個String類型參數(shù)的構造器
Constructor cst=c.getConstructor(String.class); ?//再通過調(diào)用構造器的newInstance方法來創(chuàng)建實例 ?
Object o=cst.newInstance("abc"); ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? 4.3獲取方法
//獲取這個類的除繼承父類的方法外的其他所有方法
Method[] m1=c.getDeclaredMethods();//獲取這個類的所有公有方法? ? ? ? ? ? ? ?
Method[] m2=c.getMethod(); ? //獲取指定方法?
Method m=c.getMethod("方法名"); ? ? ? ? ? ? ? ? ? ?
?? ? ? ? 4.4方法調(diào)用
//先獲取指定的方法?
Method m=c.getMethod("方法名"); //調(diào)用方法:
//當所調(diào)用的方法既有參數(shù)也有返回值時
Object result=m.invoke(參數(shù)集);//當所調(diào)用的方法沒有返回值且無參數(shù)時
m.invoke(null);