日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java findclass_带你深入了解Class类-深度分析:反射从入门到精通

發(fā)布時間:2023/12/19 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java findclass_带你深入了解Class类-深度分析:反射从入门到精通 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1. Class 類的原理

孟子曰:得人心者得天下。而在 Java 中,這個「人心」就是Class 類,獲取到Class類我們就可以為所欲為之為所欲為。下面讓我們深入「人心」,去探索 Class 類的原理。

首先了解 JVM 如何構(gòu)建實例。

1.1 JVM 構(gòu)建實例

JVM:Java Virtual Machine,Java 虛擬機。在JVM中分為棧、堆、方法區(qū)等,但這些都是JVM內(nèi)存,文中所描述的內(nèi)存指的就是JVM內(nèi)存。.class文件是字節(jié)碼文件,是通過.java文件編譯得來的。

知道上面這些內(nèi)容,我們開始創(chuàng)建實例。我們以創(chuàng)建 Person 對象舉例:

Person p = new Person()

簡簡單單通過new就創(chuàng)建了對象,那流程是什么樣的呢?見下圖

這也太粗糙了一些,那在精致一下吧。

同志們發(fā)現(xiàn)沒有,其實這里還是有些區(qū)別的,我告訴你區(qū)別是下面的字比上面多,你會打我不(別打我臉)。

粗糙的那個是通過new創(chuàng)建的對象,而精致的是通過ClassLoader操作 .class文件生成Class類,然后創(chuàng)建的對象。

其實通過new或者反射創(chuàng)建實例,都需要Class對象。

1.2 .class 文件

.class文件在文章開頭講過,是字節(jié)碼文件。.java是源程序。Java 程序是跨平臺的,一次編譯到處執(zhí)行,而編譯就是從源文件轉(zhuǎn)換成字節(jié)碼文件。

字節(jié)碼無非就是由 0 和 1 構(gòu)成的文件。

有如下一個類:

通過 vim 查看一下字節(jié)碼文件:

這啥玩意,看不懂。咱也不需要看懂,反正JVM對.class文件有它自己的讀取規(guī)則。

1.3 類加載器

還記得上面的精致圖中,我們知道是通過類加載器把.class文件加載到內(nèi)存中。具體的類加載器內(nèi)容,我會另寫一篇文章講解(寫完鏈接會更新到這里)。但是核心方法就是 loadClass(),只需要告訴它要加載的name,它就會幫你加載:

protected Class> loadClass(String name, boolean resolve)

throws ClassNotFoundException

{

synchronized (getClassLoadingLock(name)) {

// 1.檢查類是否已經(jīng)加載

Class> c = findLoadedClass(name);

if (c == null) {

long t0 = System.nanoTime();

try {

// 2.尚未加載,遵循父優(yōu)先的等級加載機制(雙親委派機制)

if (parent != null) {

c = parent.loadClass(name, false);

} else {

c = findBootstrapClassOrNull(name);

}

} catch (ClassNotFoundException e) {

// ClassNotFoundException thrown if class not found

// from the non-null parent class loader

}

if (c == null) {

// 3.如果還沒有加載成功,調(diào)用 findClass()

long t1 = System.nanoTime();

c = findClass(name);

// this is the defining class loader; record the stats

sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);

sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);

sun.misc.PerfCounter.getFindClasses().increment();

}

}

if (resolve) {

resolveClass(c);

}

return c;

}

}

// 需要重寫該方法,默認(rèn)就是拋出異常

protected Class> findClass(String name) throws ClassNotFoundException {

throw new ClassNotFoundException(name);

}

類加載器加載.class文件主要分位三個步驟

檢查類是否已經(jīng)加載,如果有就直接返回

當(dāng)前不存在該類,遵循雙親委派機制,加載 .class文件

上面兩步都失敗,調(diào)用 findClass()

因為 ClassLoader 的 findClass 方法默認(rèn)拋出異常,需要我們寫一個子類重新覆蓋它,比如:

@Override

protected Class> findClass(String name) throws ClassNotFoundException {

try {

// 通過IO流從指定位置讀取xxx.class文件得到字節(jié)數(shù)組

byte[] datas = getClassData(name);

if (null == datas){

throw new ClassNotFoundException("類沒有找到:" + name);

}

// 調(diào)用類加載器本身的defineClass()方法,由字節(jié)碼得到 class 對象

return defineClass(name, datas, 0, datas.length);

}catch (IOException e){

throw new ClassNotFoundException("類沒有找到:" + name);

}

}

private byte[] getClassData(String name) {

return byte[] datas;

}

defineClass 是通過字節(jié)碼獲取 Class 的方法,是 ClassLoader 定義的。我們具體不知道如何實現(xiàn)的,因為最終會調(diào)用一個 native 方法:

private native Class> defineClass0(String name, byte[] b, int off, int len,

ProtectionDomain pd);

private native Class> defineClass1(String name, byte[] b, int off, int len,

ProtectionDomain pd, String source);

private native Class> defineClass2(String name, java.nio.ByteBuffer b,

int off, int len, ProtectionDomain pd,

String source);

總結(jié)下類加載器加載 .class文件的步驟:

通過ClassLoader類中l(wèi)oadClass() 方法獲取Class

從緩存中查找,直接返回

緩存中不存在,通過雙親委派機制加載

上面兩步都失敗,調(diào)用findClass()

通過 IO 流從指定位置獲取到 .class文件得到字節(jié)數(shù)組

調(diào)用類加載器defineClass() 方法,由字節(jié)數(shù)組得到Class對象

1.4 Class 類

.class文件已經(jīng)被類加載器加載到內(nèi)存中并生成字節(jié)數(shù)組,JVM根據(jù)字節(jié)數(shù)組創(chuàng)建了對應(yīng)的Class對象。

接下來我們來分析下Class對象。

我們知道 Java 的對象會有下面的信息:

權(quán)限修飾符

類名和泛型信息

接口

實體

注解

構(gòu)造函數(shù)

方法

這些信息在 .class文件以 0101 表示,最后 JVM 會把.class文件的信息通過它的方式保存到Class中。

在Class中肯定有保存這些信息的字段,我們來看一下:

Class類中用ReflectionData里面的字段來與.class的內(nèi)容映射,分別映射了字段、方法、構(gòu)造器和接口。

通過annotaionData映射了注解數(shù)據(jù),其它的就不展示了,大家可以自行打開IDEA查看下Class的源碼。

那我們看看Class類的方法

1.4.1 構(gòu)造器

Class類的構(gòu)造器是私有的,只能通過JVM創(chuàng)建Class對象。所以就有了上面通過類加載器獲取Class對象的過程。

1.4.2 Class.forName

Class.forName()方法還是通過類加載器獲取Class對象。

1.4.3 newInstance

newInstance()的底層是返回?zé)o參構(gòu)造函數(shù)。

2. 總結(jié)

我們來梳理下前面的知識點:

反射的關(guān)鍵點就是獲取Class類,那系統(tǒng)是如何獲取到Class類?

是通過類加載器ClassLoader將.class文件通過字節(jié)數(shù)組的方式加載到JVM中,JVM將字節(jié)數(shù)組轉(zhuǎn)換成Class對象。那類加載器是如何加載的呢?

通過ClassLoader的loadClass()方法

從緩存中查找,直接返回

緩存中不存在,通過雙親委派機制加載

上面兩步都失敗,調(diào)用findClass()

通過 IO 流從指定位置獲取到 .class文件得到字節(jié)數(shù)組

調(diào)用類加載器defineClass() 方法,由字節(jié)數(shù)組得到Class對象

Class類的構(gòu)造器是私有的,所以需要通過JVM獲取Class。

Class.forName()也是通過類加載器獲取的Class對象。newInstance方法的底層也是返回的無參構(gòu)造函數(shù)。

總結(jié)

以上是生活随笔為你收集整理的java findclass_带你深入了解Class类-深度分析:反射从入门到精通的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。