国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Java反射機(jī)制的核心原理

一、java的核心機(jī)制

java有兩種核心機(jī)制:java虛擬機(jī)(JavaVirtual Machine)與垃圾收集機(jī)制(Garbage collection):

1、Java虛擬機(jī):是運行所有Java程序的抽象計算機(jī),是Java語言的運行環(huán)境,在其上面運行Java代碼編譯后的字節(jié)碼程序,java虛擬機(jī)實現(xiàn)了平臺無關(guān)性。

2、Java垃圾回收(Garbage Collection):自動釋放不用對象內(nèi)存空間,在java程序運行過程中自動進(jìn)行,垃圾收集機(jī)制可大大縮短編程時間,保護(hù)程序的完整性,是Java語言安全性策略的一個重要部份。

二、java虛擬機(jī)及其結(jié)構(gòu)

java垃圾回收不需要程序員手動操作,我們經(jīng)常需要關(guān)注的是java虛擬機(jī),java虛擬機(jī)承載著程序從源碼到運行的全部工作。

Java虛擬機(jī)是可運行Java代碼的假想計算機(jī),有自己想象中的硬件,如處理器、堆棧、寄存器等,還具有相應(yīng)的指令系統(tǒng),可以執(zhí)行 Java 的字節(jié)碼程序。Java語言的一個非常重要的特點就是與平臺的無關(guān)性。而使用Java虛擬機(jī)是實現(xiàn)這一特點的關(guān)鍵。Java語言使用模式Java虛擬機(jī)屏蔽了與具體平臺相關(guān)的信息,使得Java語言編譯程序只需生成在Java虛擬機(jī)上運行的目標(biāo)代碼(字節(jié)碼),就可以在多種平臺上不加修改地運行。Java虛擬機(jī)在執(zhí)行字節(jié)碼時,把字節(jié)碼解釋成具體平臺上的機(jī)器指令執(zhí)行。

對于 JVM 的基本結(jié)構(gòu),我們可以從下圖可以大致了解:


三、程序的運行過程

從源文件創(chuàng)建到程序運行,Java程序要經(jīng)過兩大步驟:編譯,運行;1、源文件由編譯器編譯成字節(jié)碼(ByteCode) 2、字節(jié)碼由java虛擬機(jī)解釋運行。

1、 第一步(編譯): 創(chuàng)建完源文件之后,程序會被編譯器編譯為.class文件。Java編譯一個類時,如果這個類所依賴的類還沒有被編譯,編譯器就會先編譯這個被依賴的類,然后引用,否則直接引用。。編譯后的字節(jié)碼文件格式主要分為兩部分:常量池和方法字節(jié)碼。

2、第二步(運行):java類運行的過程大概可分為兩個過程:1、類的加載 2、執(zhí)行。

四、類的加載

類加載過程

java程序經(jīng)過編譯后形成.class文件。通過類加載器將字節(jié)碼(.class)加載入JVM的內(nèi)存中。JVM將類加載過程分成加載,連接,初始化三個階段,其中連接階段又可分為驗證,準(zhǔn)備,解析三個階段。

JVM 的類加載是通過 ClassLoader 及其子類來完成的,類的層次關(guān)系和加載順序可以由下圖來描述:

1、Bootstrap ClassLoader啟動類加載器

負(fù)責(zé)加載$JAVA_HOME中jre/lib/里所有的 class(JDK 代表 JDK 的安裝目錄,下同),或被-Xbootclasspath參數(shù)指定的路徑中的,并且能被虛擬機(jī)識別的類庫(如 rt.jar,所有的java.*開頭的類均被 Bootstrap ClassLoader 加載)。啟動類加載器由 C++ 實現(xiàn),不是 ClassLoader 子類。無法被 Java 程序直接引用的。

2、Extension ClassLoader擴(kuò)展類加載器

該加載器由sun.misc.LauncherExtClassLoader實現(xiàn),負(fù)責(zé)加載Java平臺中擴(kuò)展功能的一些jar包,包括ExtClassLoader實現(xiàn),負(fù)責(zé)加載Java平臺中擴(kuò)展功能的一些jar包,包括JAVA_HOME中jre/lib/.jar或-Djava.ext.dirs指定目錄下的 jar 包。即JDKjrelibext目錄中,或者由 java.ext.dirs 系統(tǒng)變量指定的路徑中的所有類庫(如javax.開頭的類),開發(fā)者可以直接使用擴(kuò)展類加載器

3、App ClassLoader應(yīng)用程序類加載器

該類加載器由 sun.misc.Launcher$AppClassLoader 來實現(xiàn),負(fù)責(zé)記載 classpath 中指定的 jar 包及目錄中 class,開發(fā)者可以直接使用該類加載器,如果應(yīng)用程序中沒有自定義過自己的類加載器,一般情況下這個就是程序中默認(rèn)的類加載器。

啟動類加載器:它使用 C++ 實現(xiàn)(這里僅限于 Hotspot,也就是 JDK1.5 之后默認(rèn)的虛擬機(jī),有很多其他的虛擬機(jī)是用 Java 語言實現(xiàn)的),是虛擬機(jī)自身的一部分。

所有其他的類加載器:這些類加載器都由 Java 語言實現(xiàn),獨立于虛擬機(jī)之外,并且全部繼承自抽象類 java.lang.ClassLoader,這些類加載器需要由啟動類加載器加載到內(nèi)存中之后才能去加載其他的類。

應(yīng)用程序都是由這三種類加載器互相配合進(jìn)行加載的,我們還可以加入自定義的類加載器。

加載

加載時類加載過程的第一個階段,在加載階段,虛擬機(jī)需要完成以下三件事情:

1、通過一個類的全限定名來獲取其定義的二進(jìn)制字節(jié)流。

2、將這個字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu)。

3、在 Java 堆中生成一個代表這個類的 java.lang.Class 對象,作為對方法區(qū)中這些數(shù)據(jù)的訪問入口。

注意,這里第 1 條中的二進(jìn)制字節(jié)流并不只是單純地從 Class 文件中獲取,比如它還可以從 Jar 包中獲取、從網(wǎng)絡(luò)中獲?。ㄗ畹湫偷膽?yīng)用便是 Applet)、由其他文件生成(JSP 應(yīng)用)等。

相對于類加載的其他階段而言,加載階段(準(zhǔn)確地說,是加載階段獲取類的二進(jìn)制字節(jié)流的動作)是可控性最強(qiáng)的階段,因為開發(fā)人員既可以使用系統(tǒng)提供的類加載器來完成加載,也可以自定義自己的類加載器來完成加載。

(JVM主要在程序第一次主動使用類的時候,才會去加載該類。也就是說,JVM并不是在一開始就把一個程序就所有的類都加載到內(nèi)存中,而是到用的時候才把它加載進(jìn)來,而且只加載一次。)

加載過程中會先檢查類是否被已加載,檢查順序是自底向上,從 Custom ClassLoader 到 BootStrap ClassLoader 逐層檢查,只要某個 Classloader 已加載就視為已加載此類,保證此類只所有 ClassLoade r加載一次。而加載的順序是自頂向下,也就是由上層來逐層嘗試加載此類。

這幾種類加載器的層次關(guān)系如下圖所示:

這種層次關(guān)系稱為類加載器的雙親委派模型。雙親委派模型的工作流程是:

如果一個類加載器收到了類加載的請求,它首先不會自己去嘗試加載這個類,而是把請求委托給父加載器去完成,依次向上,因此,所有的類加載請求最終都應(yīng)該被傳遞到頂層的啟動類加載器中,只有當(dāng)父加載器在它的搜索范圍中沒有找到所需的類時,即無法完成該加載,子加載器才會嘗試自己去加載該類。

驗證

驗證的目的是為了確保 Class 文件中的字節(jié)流包含的信息符合當(dāng)前虛擬機(jī)的要求,而且不會危害虛擬機(jī)自身的安全。不同的虛擬機(jī)對類驗證的實現(xiàn)可能會有所不同,但大致都會完成以下四個階段的驗證:文件格式的驗證、元數(shù)據(jù)的驗證、字節(jié)碼驗證和符號引用驗證。

準(zhǔn)備

準(zhǔn)備階段是正式為類變量分配內(nèi)存并設(shè)置類變量初始值的階段,這些內(nèi)存都將在方法區(qū)中分配。對于該階段有以下幾點需要注意:

1、這時候進(jìn)行內(nèi)存分配的僅包括類變量(static),而不包括實例變量,實例變量會在對象實例化時隨著對象一塊分配在 Java 堆中。

2、這里所設(shè)置的初始值通常情況下是數(shù)據(jù)類型默認(rèn)的零值(如 0、0L、null、false 等),而不是被在 Java 代碼中被顯式地賦予的值。

解析

解析階段是虛擬機(jī)將常量池中的符號引用轉(zhuǎn)化為直接引用的過程。

解析動作主要針對類或接口、字段、類方法、接口方法四類符號引用進(jìn)行,分別對應(yīng)于常量池中的 CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info、CONSTANT_InterfaceMethodref_info 四種常量類型。

1、類或接口的解析:判斷所要轉(zhuǎn)化成的直接引用是對數(shù)組類型,還是普通的對象類型的引用,從而進(jìn)行不同的解析。

2、字段解析:對字段進(jìn)行解析時,會先在本類中查找是否包含有簡單名稱和字段描述符都與目標(biāo)相匹配的字段,如果有,則查找結(jié)束;如果沒有,則會按照繼承關(guān)系從上往下遞歸搜索該類所實現(xiàn)的各個接口和它們的父接口,還沒有,則按照繼承關(guān)系從上往下遞歸搜索其父類,直至查找結(jié)束。

初始化

類初始化是類加載過程的最后一個階段,到初始化階段,才真正開始執(zhí)行類中的 Java 程序代碼。虛擬機(jī)規(guī)范嚴(yán)格規(guī)定了有且只有四種情況必須立即對類進(jìn)行初始化:

1、 遇到 new、getstatic、putstatic、invokestatic 這四條字節(jié)碼指令時,如果類還沒有進(jìn)行過初始化,則需要先觸發(fā)其初始化。生成這四條指令最常見的 Java 代碼場景是:使用 new 關(guān)鍵字實例化對象時、讀取或設(shè)置一個類的靜態(tài)字段(static)時(被 static 修飾又被 final 修飾的,已在編譯期把結(jié)果放入常量池的靜態(tài)字段除外)、以及調(diào)用一個類的靜態(tài)方法時。

2、 使用 Java.lang.refect 包的方法對類進(jìn)行反射調(diào)用時,如果類還沒有進(jìn)行過初始化,則需要先觸發(fā)其初始化。

3、當(dāng)初始化一個類的時候,如果發(fā)現(xiàn)其父類還沒有進(jìn)行初始化,則需要先觸發(fā)其父類的初始化。

4、當(dāng)虛擬機(jī)啟動時,用戶需要指定一個要執(zhí)行的主類,虛擬機(jī)會先執(zhí)行該主類。

虛擬機(jī)規(guī)定只有這四種情況才會觸發(fā)類的初始化,稱為對一個類進(jìn)行主動引用,除此之外所有引用類的方式都不會觸發(fā)其初始化,稱為被動引用。

五、靜態(tài)加載和動態(tài)加載

Java初始化一個類的時候可以用new 操作符來初始化,也可通過Class.forName的方式來得到一個Class類型的實例,然后通過這個Class類型的實例的newInstance來初始化.我們把前者叫做JAVA的靜態(tài)加載,把后者叫做動態(tài)加載.。

有時候我們說某個語言具有很強(qiáng)的動態(tài)性,有時候我們會區(qū)分動態(tài)和靜態(tài)的不同技術(shù)與作法。我們朗朗上口動態(tài)綁定(dynamic binding)、動態(tài)鏈接(dynamic linking)、動態(tài)加載(dynamic loading)等。然而“動態(tài)”一詞其實沒有絕對而普遍適用的嚴(yán)格定義,有時候甚至像面向?qū)ο螽?dāng)初被導(dǎo)入編程領(lǐng)域一樣,一人一把號,各吹各的調(diào)。

一般而言,開發(fā)者社群說到動態(tài)語言,大致認(rèn)同的一個定義是:“程序運行時,允許改變程序結(jié)構(gòu)或變量類型,這種語言稱為動態(tài)語言”。從這個觀點看,Perl,Python,Ruby是動態(tài)語言,C++,Java,C#不是動態(tài)語言。

盡管在這樣的定義與分類下Java不是動態(tài)語言,它卻有著一個非常突出的動態(tài)相關(guān)機(jī)制:Reflection。Java程序可以加載一個運行時才得知名稱的class,獲悉其完整構(gòu)造(但不包括methods定義),并生成其對象實體、或?qū)ζ鋐ields設(shè)值、或喚起其methods。

1、靜態(tài)加載的時候如果在運行環(huán)境中找不到要初始化的類,拋出的是NoClassDefFoundError,它在JAVA的異常體系中是一個Error.

2、動態(tài)態(tài)加載的時候如果在運行環(huán)境中找不到要初始化的類,拋出的是ClassNotFoundException,它在JAVA的異常體系中是一個checked異常,在寫代碼的時候就需要catch.

六、反射

JAVA反射機(jī)制:

在運行狀態(tài)中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調(diào)用它的任意一個方法和屬性;這種動態(tài)獲取的信息以及動態(tài)調(diào)用對象的方法的功能稱為java語言的反射機(jī)制。

Java反射機(jī)制主要提供了以下功能:

在運行時判斷任意一個對象所屬的類;在運行時構(gòu)造任意一個類的對象;在運行時判斷任意一個類所具有的成員變量和方法;在運行時調(diào)用任意一個對象的方法;生成動態(tài)代理。

Java有個Object 類,是所有Java 類的繼承根源,其內(nèi)聲明了數(shù)個應(yīng)該在所有Java 類中被改寫的方法:hashCode()、equals()、clone()、toString()、getClass()等。其中g(shù)etClass()返回一個Class 對象。

【Class 類十分特殊。它和一般類一樣繼承自O(shè)bject,其實體用以表達(dá)Java程序運行時的classes和interfaces,也用來表達(dá)enum、array、primitive Java types(boolean, byte, char, short, int, long, float, double)以及關(guān)鍵詞void。當(dāng)一個class被加載,或當(dāng)加載器(class loader)的defineClass()被JVM調(diào)用,JVM 便自動產(chǎn)生一個Class 對象?!?/p>

如果您想借由“修改Java標(biāo)準(zhǔn)庫源碼”來觀察Class 對象的實際生成時機(jī)(例如在Class的constructor內(nèi)添加一個println()),這樣是行不通的!因為Class并沒有public constructor。

Class是Reflection故事起源。針對任何您想探勘的類,唯有先為它產(chǎn)生一個Class 對象,接下來才能經(jīng)由后者喚起為數(shù)十多個的Reflection APIs。Reflection機(jī)制允許程序在正在執(zhí)行的過程中,利用Reflection APIs取得任何已知名稱的類的內(nèi)部信息,包括:package、 type parameters、 superclass、 implemented interfaces、 inner classes、 outer classes、 fields、 constructors、 methods、 modifiers等,并可以在執(zhí)行的過程中,動態(tài)生成instances、變更fields內(nèi)容或喚起methods。

從Class中獲取信息

Class類提供了大量的實例方法來獲取該Class對象所對應(yīng)的詳細(xì)信息,Class類大致包含如下方法,其中每個方法都包含多個重載版本,因此我們只是做簡單的介紹,詳細(xì)請參考JDK文檔

獲取類內(nèi)信息

獲取內(nèi)容 方法簽名構(gòu)造器 Constructor getConstructor(Class... parameterTypes)包含的方法 Method getMethod(String name, Class... parameterTypes)包含的屬性 Field getField(String name)包含的Annotation A getAnnotation(Class annotationClass)內(nèi)部類 Class[] getDeclaredClasses()外部類 Class getDeclaringClass()所實現(xiàn)的接口 Class[] getInterfaces()修飾符 int getModifiers()所在包 Package getPackage()類名 String getName()簡稱 String getSimpleName()

一些判斷類本身信息的方法

判斷內(nèi)容 方法簽名注解類型? boolean isAnnotation()使用了該Annotation修飾? boolean isAnnotationPresent(Class annotationClass)匿名類? boolean isAnonymousClass()數(shù)組? boolean isArray()枚舉? boolean isEnum()原始類型? boolean isPrimitive()接口? boolean isInterface()obj是否是該Class的實例 boolean isInstance(Object obj)

(1)獲取class


主有三種獲得class的途徑,使用時要注意區(qū)別

1、 a,類型.class 如: String.class使用類名加“.class”的方式即會返回與該類對應(yīng)的Class對象。這個方法可以直接獲得與指定類關(guān)聯(lián)的Class對象,而并不需要有該類的對象存在。

2、 b,Class.forName('類名');該方法可以根據(jù)字符串參數(shù)所指定的類名獲取與該類關(guān)聯(lián)的Class對象。如果該類還沒有被裝入,該方法會將該類裝入JVM。forName方法的參數(shù)是類的完 整限定名(即包含包名)。通常用于在程序運行時根據(jù)類名動態(tài)的載入該類并獲得與之對應(yīng)的Class對象。

3、 c, obj.getClass();所有Java對象都具備這個方法,該方法用于返回調(diào)用該方法的對象的所屬類關(guān)聯(lián)的

(2)獲取構(gòu)造方法

Class類提供了四個public方法,用于獲取某個類的構(gòu)造方法:

1、Constructor getConstructor(Class[] params)根據(jù)構(gòu)造函數(shù)的參數(shù),返回一個具體的具有public屬性的構(gòu)造函數(shù)

2、Constructor getConstructors() 返回所有具有public屬性的構(gòu)造函數(shù)數(shù)組

3、Constructor getDeclaredConstructor(Class[] params) 根據(jù)構(gòu)造函數(shù)的參數(shù),返回一個具體的構(gòu)造函數(shù)(不分public和非public屬性)

4、Constructor getDeclaredConstructors() 返回該類中所有的構(gòu)造函數(shù)數(shù)組(不分public和非public屬性)

  • 1 反射出無參的構(gòu)造方法并得到對象
  • * 注意:
  • * 1 在Class.forName()中應(yīng)該傳入含有包名的類全名
  • * 2 newInstance()方法的本質(zhì)是調(diào)用類的無參Public構(gòu)造方法
  • /

  • String className1='cn.testreflect.Worker';

  • Class clazz1=Class.forName(className1);

  • Object object1=clazz1.newInstance();

  • System.out.println('object1.toString()='+object1.toString());

  • /

    *
  • * 2 反射出帶參數(shù)的構(gòu)造方法并得到對象
  • */
  • String className2='cn.testreflect.Worker';
  • Class clazz2=Class.forName(className2);
  • Constructor constructor1=clazz2.getConstructor(int.class,String.class);
  • Object object2=constructor1.newInstance(18,'小明');
  • System.out.println('object2.toString()='+object2.toString());
  • (3)獲取類的成員方法
  • 與獲取構(gòu)造方法的方式相同,存在四種獲取成員方法的方式:
  • 1、Method getMethod(String name, Class[] params) 根據(jù)方法名和參數(shù),返回一個具體的具有public屬性的方法
  • 2、Method[] getMethods() 返回所有具有public屬性的方法數(shù)組
  • 3、Method getDeclaredMethod(String name, Class[] params) 根據(jù)方法名和參數(shù),返回一個具體的方法(不分public和非public屬性)
  • 4、Method[] getDeclaredMethods() 返回該類中的所有的方法數(shù)組(不分public和非public屬性)
* 調(diào)用對象的帶參數(shù)的方法  */  String className5='cn.testreflect.Worker';  Class clazz5=Class.forName(className5);  Method method=clazz5.getMethod('printMessage', String.class,int.class,int.class);  Object object5=clazz5.newInstance();  method.invoke(object5, '周星星',50,9527);  } catch (Exception e) {  System.out.println(e.toString());  }

(4)獲取類的成員變量(成員屬性)

存在四種獲取成員屬性的方法

1、Field getField(String name) 根據(jù)變量名,返回一個具體的具有public屬性的成員變量

2、Field[] getFields() 返回具有public屬性的成員變量的數(shù)組

3、Field getDeclaredField(String name) 根據(jù)變量名,返回一個成員變量(不分public和非public屬性)

4、Field[] getDelcaredFields() 返回所有成員變量組成的數(shù)組(不分public和非public屬性)

* 1 獲取類的私有字段  * 注意:  * 獲取共有字段應(yīng)調(diào)用clazz3.getField(name)方法  */  String className3='cn.testreflect.Worker';  Class clazz3=Class.forName(className3);  Field ageField1=clazz3.getDeclaredField('age');  System.out.println('ageField1='+ageField1);  /**  * 2 獲取和更改某個對象的私有字段  * 即模擬get()和set()方法  */  String className4='cn.testreflect.Worker';  Class clazz4=Class.forName(className4);  Field ageField2=clazz4.getDeclaredField('age');  Object object4=constructor1.newInstance(18,'小明');  //取消訪問私有字段的合法性檢查  ageField2.setAccessible(true);  //獲取對象的私有字段  Object ageObject4=ageField2.get(object4);  System.out.println('ageObject4='+ageObject4);  //再更改對象的私有字段的值  ageField2.set(object4, 9527);  //重新獲得  Object ageObject5=ageField2.get(object4);  System.out.println('ageObject5='+ageObject5);
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
第五章Java虛擬機(jī)(Chapter Five: The Java Virtual Mac...
JVM總結(jié) ----JVM體系結(jié)構(gòu)
Java程序員從笨鳥到菜鳥之(九十三)深入java虛擬機(jī)(二)——類加載器詳解(上)
面試阿里高級架構(gòu)師之JVM篇
類加載機(jī)制(類加載過程和類加載器)
JVM類加載的那些事
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服