偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

反射必殺技:深入了解Class類,讓你一通百通

開(kāi)發(fā) 后端
孟子曰:得人心者得天下。而在 Java 中,這個(gè)「人心」就是 Class 類,獲取到 Class 類我們就可以為所欲為之為所欲為。下面讓我們深入「人心」,去探索 Class 類的原理。

1. Class 類的原理

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

[[287309]]

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

1.1 JVM 構(gòu)建實(shí)例

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

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

  1. Person p = new Person() 

簡(jiǎn)簡(jiǎn)單單通過(guò) new 就創(chuàng)建了對(duì)象,那流程是什么樣的呢?見(jiàn)下圖: 

反射必殺技:深入了解Class類,讓你一通百通

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

反射必殺技:深入了解Class類,讓你一通百通

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

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

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

1.2 .class 文件

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

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

有如下一個(gè)類: 

反射必殺技:深入了解Class類,讓你一通百通

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

反射必殺技:深入了解Class類,讓你一通百通

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

1.3 類加載器

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

  1. protected Class<?> loadClass(String name, boolean resolve) 
  2.     throws ClassNotFoundException 
  3.     synchronized (getClassLoadingLock(name)) { 
  4.         // 1.檢查類是否已經(jīng)加載 
  5.         Class<?> c = findLoadedClass(name); 
  6.         if (c == null) { 
  7.             long t0 = System.nanoTime(); 
  8.             try { 
  9.                 // 2.尚未加載,遵循父優(yōu)先的等級(jí)加載機(jī)制(雙親委派機(jī)制) 
  10.                 if (parent != null) { 
  11.                     c = parent.loadClass(namefalse); 
  12.                 } else { 
  13.                     c = findBootstrapClassOrNull(name); 
  14.                 } 
  15.             } catch (ClassNotFoundException e) { 
  16.                 // ClassNotFoundException thrown if class not found 
  17.                 // from the non-null parent class loader 
  18.             } 
  19.  
  20.             if (c == null) { 
  21.                 // 3.如果還沒(méi)有加載成功,調(diào)用 findClass() 
  22.                 long t1 = System.nanoTime(); 
  23.                 c = findClass(name); 
  24.  
  25.                 // this is the defining class loader; record the stats 
  26.                 sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); 
  27.                 sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); 
  28.                 sun.misc.PerfCounter.getFindClasses().increment(); 
  29.             } 
  30.         } 
  31.         if (resolve) { 
  32.             resolveClass(c); 
  33.         } 
  34.         return c; 
  35.     } 
  36.  
  37. // 需要重寫(xiě)該方法,默認(rèn)就是拋出異常 
  38. protected Class<?> findClass(String name) throws ClassNotFoundException { 
  39.     throw new ClassNotFoundException(name); 
  1. 類加載器加載 .class 文件主要分位三個(gè)步驟
  2. 檢查類是否已經(jīng)加載,如果有就直接返回
  3. 當(dāng)前不存在該類,遵循雙親委派機(jī)制,加載 .class 文件

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

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

  1. @Override 
  2.     protected Class<?> findClass(String name) throws ClassNotFoundException { 
  3.         try { 
  4.             // 通過(guò)IO流從指定位置讀取xxx.class文件得到字節(jié)數(shù)組 
  5.             byte[] datas = getClassData(name); 
  6.             if (null == datas){ 
  7.                 throw new ClassNotFoundException("類沒(méi)有找到:" + name); 
  8.             } 
  9.             // 調(diào)用類加載器本身的defineClass()方法,由字節(jié)碼得到 class 對(duì)象 
  10.             return defineClass(name, datas, 0, datas.length); 
  11.         }catch (IOException e){ 
  12.             throw new ClassNotFoundException("類沒(méi)有找到:" + name); 
  13.         } 
  14.     } 
  15.  
  16.     private byte[] getClassData(String name) { 
  17.         return byte[] datas; 
  18.     } 

defineClass 是通過(guò)字節(jié)碼獲取 Class 的方法,是 ClassLoader 定義的。我們具體不知道如何實(shí)現(xiàn)的,因?yàn)樽罱K會(huì)調(diào)用一個(gè) native 方法:

  1. private native Class<?> defineClass0(String name, byte[] b, int offint len, 
  2.                                          ProtectionDomain pd); 
  3.  
  4.     private native Class<?> defineClass1(String name, byte[] b, int offint len, 
  5.                                          ProtectionDomain pd, String source); 
  6.  
  7.     private native Class<?> defineClass2(String name, java.nio.ByteBuffer b, 
  8.                                          int offint len, ProtectionDomain pd, 
  9.                                          String source); 

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

  • 通過(guò) ClassLoader 類中 loadClass() 方法獲取 Class
  • 從緩存中查找,直接返回
  • 緩存中不存在,通過(guò)雙親委派機(jī)制加載
  • 上面兩步都失敗,調(diào)用 findClass()通過(guò) IO 流從指定位置獲取到 .class 文件得到字節(jié)數(shù)組調(diào)用類加載器 defineClass() 方法,由字節(jié)數(shù)組得到 Class 對(duì)象

1.4 Class 類

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

接下來(lái)我們來(lái)分析下 Class 對(duì)象。 

反射必殺技:深入了解Class類,讓你一通百通

我們知道 Java 的對(duì)象會(huì)有下面的信息:

  1. 權(quán)限修飾符
  2. 類名和泛型信息
  3. 接口
  4. 實(shí)體
  5. 注解
  6. 構(gòu)造函數(shù)
  7. 方法

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

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

反射必殺技:深入了解Class類,讓你一通百通

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

反射必殺技:深入了解Class類,讓你一通百通

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

那我們看看 Class 類的方法

1.4.1 構(gòu)造器 

反射必殺技:深入了解Class類,讓你一通百通

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

1.4.2 Class.forName 

反射必殺技:深入了解Class類,讓你一通百通

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

1.4.3 newInstance 

反射必殺技:深入了解Class類,讓你一通百通

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

2. 總結(jié)

我們來(lái)梳理下前面的知識(shí)點(diǎn):

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

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

  • 通過(guò) ClassLoader 的 loadClass() 方法
  • 從緩存中查找,直接返回
  • 緩存中不存在,通過(guò)雙親委派機(jī)制加載
  • 上面兩步都失敗,調(diào)用 findClass()通過(guò) IO 流從指定位置獲取到 .class 文件得到字節(jié)數(shù)組調(diào)用類加載器 defineClass() 方法,由字節(jié)數(shù)組得到 Class 對(duì)象

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

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

 

責(zé)任編輯:武曉燕 來(lái)源: 今日頭條
相關(guān)推薦

2023-07-18 06:48:03

2010-05-14 13:05:57

2014-04-22 10:50:31

統(tǒng)一通信UCBYOD

2018-09-21 14:32:00

iPaas云應(yīng)用部署

2010-08-24 14:57:33

外企職場(chǎng)

2011-06-27 14:56:49

SEO

2010-01-06 17:18:54

Linux常用軟件

2025-01-23 08:38:46

2024-08-09 12:11:07

2013-05-10 09:23:14

iPaaS混合云集成云集成

2010-05-12 18:04:00

統(tǒng)一通信服務(wù)

2021-02-02 10:55:09

等級(jí)保護(hù)2.0信息安全網(wǎng)絡(luò)安全

2009-07-22 15:02:18

2010-08-11 16:43:05

職場(chǎng)

2012-10-18 13:48:31

統(tǒng)一通信UC

2010-11-18 10:52:54

統(tǒng)一通信

2009-10-13 16:38:04

強(qiáng)行關(guān)閉VMware虛

2010-05-21 12:33:28

統(tǒng)一通信技術(shù)平臺(tái)

2010-05-21 11:00:59

2023-04-07 17:44:43

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)