溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java開(kāi)發(fā)中類的加載及反射機(jī)制是什么

發(fā)布時(shí)間:2021-07-12 14:17:27 來(lái)源:億速云 閱讀:114 作者:chen 欄目:編程語(yǔ)言

本篇內(nèi)容介紹了“Java開(kāi)發(fā)中類的加載及反射機(jī)制是什么”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

JAVA中類文件加載是動(dòng)態(tài)的。JVM指令是被封裝在了.class文件里面,而.class文件的加載過(guò)程是動(dòng)態(tài)的,也就是說(shuō)當(dāng)我們用到的時(shí)候才會(huì)去加載,如果不用的話,就不會(huì)去加載我們的類。這里所說(shuō)的用到包括兩種方式,***種就是new一個(gè)對(duì)象的時(shí)候(這個(gè)時(shí)候要特別注意,當(dāng)設(shè)計(jì)到多態(tài)的時(shí)候,就會(huì)有一點(diǎn)點(diǎn)變化,這時(shí)候編譯器會(huì)做一些優(yōu)化,這樣以來(lái)當(dāng)加載的時(shí)候會(huì)提前加載設(shè)計(jì)到多態(tài)的類,關(guān)于這一點(diǎn)下面有個(gè)例子(example 1)來(lái)說(shuō)明。另一種就是當(dāng)一個(gè)類的靜態(tài)代碼被調(diào)用的時(shí)候。

java 代碼
//example 1
//Zoo.java
abstract class Animal {
Animal(){
System.out.println("Animal constructor");
}
}
class Tiger extends Animal {
Tiger(){
System.out.println("Tig constructor ");
}
}
class Dog extends Animal {
Dog(){
System.out.println("Dog Constructor ");
}
}
public class Zoo {
private Animal am; //Example 1.1
//private Dog am; Example 1.2
private Tiger tiger;
Zoo(){
tiger = new Tiger();
am = new Dog();
}
public static void main(String [] args){
System.out.println("new Zoo before");
Zoo z = new Zoo();
System.out.println("new Zoo after ");
}
}

我們可以看出:當(dāng)我們將子類對(duì)象賦值給父類時(shí),編譯器會(huì)做一點(diǎn)優(yōu)化,于是加載器在還沒(méi)有new子類對(duì)象的時(shí)候已經(jīng)加載了父類以及子類(example1.1結(jié)果),當(dāng)不存在多態(tài)的時(shí)候,我們可以看到是當(dāng)要new Dog()的時(shí)候才會(huì)加載Dog以及父類。無(wú)論何種方式,在new之前,類確實(shí)已經(jīng)加載到了內(nèi)存中。

JAVA為我們提供了兩種動(dòng)態(tài)機(jī)制。***種是隱式機(jī)制。其實(shí)new一個(gè)對(duì)象和調(diào)用類的靜態(tài)方法時(shí),就是隱式機(jī)制在工作。第二種是顯示機(jī)制。顯示的機(jī)制又有兩種策略(***種是用java.lang.Class的forName(String str)方法,第二種是用java.lang.ClassLoader的loadClass())。

***種:利用forName方法

當(dāng)我們查API文檔就會(huì)發(fā)現(xiàn)forName方法有兩種形式。分別如下:

public static Class<?> forName(String className)
throws ClassNotFoundException
public static Class<?> forName(String name,
boolean initialize,
ClassLoader loader)
throws ClassNotFoundException

先來(lái)說(shuō)說(shuō)第二種方法:第二個(gè)方法值得注意的就是第二個(gè)參數(shù)boolean initialize,如果我們把這個(gè)參數(shù)設(shè)置為false,那么當(dāng)我們加載完類后就不會(huì)執(zhí)行靜態(tài)代碼和靜態(tài)的初始化動(dòng)作。只有當(dāng)我們new一個(gè)對(duì)象的時(shí)候才會(huì)初始化。而第三個(gè)參數(shù)是用來(lái)指明類的加載器的。

如果查看java.lang.Class類的源代碼,上述兩種方法最終都會(huì)調(diào)用Class類中的私有的native方法forName0(),此方法的聲明如下:

private static native Class forName0(String name, boolean init,ClassLoader loader)
throws ClassNotFoundException;

所以當(dāng)我們調(diào)用Class.forName(name )時(shí),其實(shí)是在方法內(nèi)部調(diào)用了:

forName0(name, true, ClassLoader.getCallerClassLoader());

當(dāng)我們調(diào)用Class.forName(name, initialize, loader )的時(shí)候,實(shí)際上此方法內(nèi)部調(diào)用了:

forName0(name, initialize, loader);

下面看一個(gè)例子,如果方法中第二個(gè)參數(shù)為false的情況:

java 代碼
//example 2.1
//Zoo.java
abstract class Animal {
static {
System.out.println("Animal static code block ");
}
Animal(){
System.out.println("Animal constructor");
}
}
class Tiger extends Animal {
Tiger(){
System.out.println("Tig constructor ");
}
}
class Dog extends Animal {
Dog(){
System.out.println("Dog Constructor ");
}
}
public class Zoo {
public static void main(String [] args)throws Exception {
System.out.println("new Zoo before");
Zoo z = new Zoo();
Class c = Class.forName("Dog",false,z.getClass().getClassLoader());
System.out.println("initilize before ");
Animal dog = (Animal)c.newInstance();
System.out.println("new Zoo after ");
}
}

類加載完成后并沒(méi)有立即執(zhí)行靜態(tài)初始化代碼,而是到了實(shí)例化的時(shí)候才進(jìn)行了靜態(tài)初始化。有時(shí)候我們會(huì)說(shuō)靜態(tài)代碼是在類***次被加載時(shí)執(zhí)行的,并且只執(zhí)行一次。其實(shí)這是對(duì)與new一個(gè)對(duì)象,***次訪問(wèn)類的靜態(tài)代碼以及第二個(gè)參數(shù)為true時(shí)而言的,對(duì)于動(dòng)態(tài)的加載來(lái)說(shuō),如果forName方法的第二個(gè)參數(shù)設(shè)置為false,那么就是在實(shí)例化的時(shí)候才會(huì)執(zhí)行靜態(tài)初始化。當(dāng)然默認(rèn)情況下第二個(gè)參數(shù)是true。

第二種方法:利用Class對(duì)象獲取的ClassLoader裝載

下面是一個(gè)簡(jiǎn)單的例子:

java 代碼
//Example 2.2
//Zoo.java
abstract class Animal {
static {
System.out.println("Animal static code block ");
}
Animal(){
System.out.println("Animal constructor");
}
}
class Tiger extends Animal {
Tiger(){
System.out.println("Tig constructor ");
}
}
class Dog extends Animal {
Dog(){
System.out.println("Dog Constructor ");
}
}
public class Zoo {
public static void main(String [] args)throws Exception {
Class c = Zoo.class;
ClassLoader loader = c.getClassLoader();
System.out.println("loader before");
Class dog = loader.loadClass("Dog");
System.out.println("instance before ");
Animal an = (Animal)dog.newInstance();
}
}

loader完成以后并沒(méi)有立即進(jìn)行靜態(tài)代碼的執(zhí)行。只有當(dāng)newInstance()的時(shí)候才執(zhí)行靜態(tài)初始化,這和把public static Class forName(String name, boolean initialize, ClassLoader loader)的第二個(gè)參數(shù)指定為false的情況完全一樣。其實(shí)每當(dāng)我們寫(xiě)完一個(gè)編譯單元以后就會(huì)得到一個(gè).calss文件,這個(gè)文件中就包含了該類的Class對(duì)象。JVM就是利用這個(gè)class對(duì)象來(lái)進(jìn)行動(dòng)態(tài)裝載類的。

“Java開(kāi)發(fā)中類的加載及反射機(jī)制是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI