反射&枚舉
課程目標(biāo)
1. 【理解】類加載器
2. 【理解】什么是反射
3. 【掌握】獲取Class對象的三種方式
4. 【掌握】反射獲取構(gòu)造方法并創(chuàng)建對象
5. 【掌握】反射獲取成員變量并使用
6. 【掌握】反射獲取成員方法并使用
7. 【掌握】反射綜合案例
8. 【理解】枚舉
B友:https://www.bilibili.com/video/BV1QG4y1J76q/
VIP服務(wù)課程:https://edu.51cto.com/course/32767.html
類加載器
類加載
當(dāng)程序要使用某個(gè)類時(shí),如果該類還未被加載到內(nèi)存中,則系統(tǒng)會通過類的【加載】,【連接】,【初始化】 這三個(gè)步驟來對類進(jìn)行初始化。
如果不出現(xiàn)意外情況,JVM將會連續(xù)完成這三個(gè)步驟,所以有時(shí)也把這三個(gè)步驟統(tǒng)稱為類加載或者類初始化。
一個(gè)類的生命周期包括了 “加載”、“驗(yàn)證”、“準(zhǔn)備”、“解析”、“初始化”、“使用”、“卸載” 這七個(gè)階段, 我們只研究前五個(gè)階段,這五個(gè)階段又可以分為 “加載”、“連接、驗(yàn)證,解析” 、 “初始化”。
當(dāng)程序主動使用某個(gè)類時(shí),如果該類還未被加載到內(nèi)存中,則系統(tǒng)會通過如下三個(gè)步驟來對該類進(jìn)行初始化。
類的加載
類的加載就是指將class文件讀入內(nèi)存,并為之創(chuàng)建一個(gè)Class對象。任何類被使用時(shí)系統(tǒng)都會建立一個(gè)Class對象,用于加載二進(jìn)制數(shù)據(jù),類的加載主要做三件事情:
-
找到類文件(通過類的全限定名來獲取定義此類的二進(jìn)制字節(jié)流)
首先會根據(jù)各種途徑(比如網(wǎng)絡(luò)下載、數(shù)據(jù)庫提取、從jar,zip中讀取等)獲取類的二進(jìn)制數(shù)據(jù)
-
放入方法區(qū)(將這個(gè)字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu))
把獲取到的二進(jìn)制數(shù)據(jù)讀入內(nèi)存,存儲在運(yùn)行時(shí)數(shù)據(jù)區(qū)的方法區(qū),
這些二進(jìn)制數(shù)據(jù)所代表的存儲結(jié)構(gòu)會被轉(zhuǎn)化為方法區(qū)中運(yùn)行時(shí)的數(shù)據(jù)結(jié)構(gòu)
-
開個(gè)入口(生成一個(gè)代表此類的java.lang.Class對象,作為訪問方法區(qū)這些數(shù)據(jù)結(jié)構(gòu)的入口)
在方法區(qū)中創(chuàng)建相應(yīng)的Class對象(這里的Class對象與平時(shí)所說的對象是不一樣的,
當(dāng)使用new創(chuàng)建實(shí)例對象時(shí),就會通過Class對象在堆中創(chuàng)建實(shí)例對象)用來封裝保存在方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)
類的連接
-
【驗(yàn)證階段】:用于檢驗(yàn)被加載的類是否有正確的內(nèi)部結(jié)構(gòu),并和其他類協(xié)調(diào)一致
文件格式驗(yàn)證:驗(yàn)證字節(jié)流是否符合class文件的規(guī)范,確保輸入的字節(jié)流能正確解析并存儲到方法區(qū)
元數(shù)據(jù)驗(yàn)證:對字節(jié)碼描述的信息進(jìn)行語義分析,保證其描述的信息符合規(guī)范要求。
字節(jié)碼驗(yàn)證:這個(gè)階段是比較復(fù)雜的,通過數(shù)據(jù)流和控制流分析,對類的方法體進(jìn)行校驗(yàn),確保程序的合法性。符號引用驗(yàn)證:這里的符號引用不單單指類的,也包括方法。
? 發(fā)生在符號引用轉(zhuǎn)為直接引用的時(shí)候,也就是解析階段,
? 對常量池中各種符號引用的信息進(jìn)行匹配性校驗(yàn),確保解析動作正確執(zhí)行 -
【準(zhǔn)備階段】:負(fù)責(zé)為類的類變量分配內(nèi)存,并設(shè)置默認(rèn)初始化值
需要注意的是:
* 靜態(tài)變量只會給默認(rèn)值。 * 例:public static int value = 123; // 此時(shí)賦給value的值是0,不是123。 * 靜態(tài)常量(static final修飾的)則會直接賦值。 * 例:public static final int value = 123; // 此時(shí)賦給value的值是123。
-
【解析階段】:將類的二進(jìn)制數(shù)據(jù)中的符號引用替換為直接引用
類的初始化
類的初始化的主要工作是為靜態(tài)變量賦程序設(shè)定的初值。
類的初始化步驟
- 假如類還未被加載和連接,則程序先加載并連接該類
- 假如該類的直接父類還未被初始化,則先初始化其直接父類
- 假如類中有初始化語句,則系統(tǒng)依次執(zhí)行這些初始化語句
- 注意:在執(zhí)行第2個(gè)步驟的時(shí)候,系統(tǒng)對直接父類的初始化步驟也遵循初始化步驟1-3
類的初始化時(shí)機(jī)
- 創(chuàng)建類的實(shí)例
- 調(diào)用類的類方法
- 訪問類或者接口的類變量,或者為該類變量賦值
- 使用反射方式來強(qiáng)制創(chuàng)建某個(gè)類或接口對應(yīng)的java.lang.Class對象
- 初始化某個(gè)類的子類
- 直接使用java.exe命令來運(yùn)行某個(gè)主類
類加載器
類加載器的作用
負(fù)責(zé)將.class文件加載到內(nèi)存中,并為之生成對應(yīng)的 java.lang.Class 對象。雖然我們不用過分關(guān)心類加載機(jī)制,但是了解這個(gè)機(jī)制我們就能更好的理解程序的運(yùn)行!
簡單來說:類加載器的作用,就是把class文件裝進(jìn)虛擬機(jī)
類加載機(jī)制
-
全盤負(fù)責(zé)
就是當(dāng)一個(gè)類加載器負(fù)責(zé)加載某個(gè)Class時(shí),該Class所依賴的和引用的其他Class也將由該類加載器負(fù)責(zé)載入,除非顯示使用另外一個(gè)類加載器來載入
-
父類委托
就是當(dāng)一個(gè)類加載器負(fù)責(zé)加載某個(gè)Class時(shí),先讓父類加載器試圖加載該Class,只有在父類加載器無法加載該類時(shí)才嘗試從自己的類路徑中加載該類
-
緩存機(jī)制
保證所有加載過的Class都會被緩存,當(dāng)程序需要使用某個(gè)Class對象時(shí),類加載器先從緩存區(qū)中搜索該Class,只有當(dāng)緩存區(qū)中不存在該Class對象時(shí),系統(tǒng)才會讀取該類對應(yīng)的二進(jìn)制數(shù)據(jù),并將其轉(zhuǎn)換成Class對象,存儲到緩存區(qū)
雙親委派機(jī)制
-
當(dāng)前ClassLoader首先從自己已經(jīng)加載的類中查詢是否此類已經(jīng)加載,如果已經(jīng)加載則直接返回原來已經(jīng)加載的類。每個(gè)類加載器都有自己的加載緩存,當(dāng)一個(gè)類被加載了以后就會放入緩存,等下次加載的時(shí)候就可以直接返回了。
-
當(dāng)前ClassLoader的緩存中沒有找到被加載的類的時(shí)候,委托父類加載器去加載,父類加載器采用同樣的策略,首先查看自己的緩存,然后委托父類的父類去加載, 一直到bootstrp ClassLoader.
-
當(dāng)所有的父類加載器都沒有加載的時(shí)候,再由當(dāng)前的類加載器加載,并將其放入它自己的緩存中,以便下次有加載請求的時(shí)候直接返回。
這樣做的好處是什么?
1.避免重復(fù)加載。當(dāng)父親已經(jīng)加載了該類的時(shí)候,就沒有必要子ClassLoader再加載一次。
2.為了安全。避免核心類,比如String被替換。
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-dntytLVb-1692620952897)(asseits/1de2c4d28014486fa71fdcd0938cd31a.png)]
Java中的內(nèi)置類加載器
當(dāng)JVM啟動的時(shí)候,Java缺省開始使用如下三種類加載器
-
Bootstrap ClassLoader
引導(dǎo)類加載器(根類加載器), 用來加載 Java 的核心庫,是用原生代碼來實(shí)現(xiàn)的,
比如:System.String等,jre的lib下rt.jar文件中 -
Platform ClassLoader
平臺類加載器可以看到所有平臺類 ,平臺類包括由平臺類加載器或其祖先定義的Java SE平臺API,其實(shí)現(xiàn)類和JDK特定的運(yùn)行時(shí)類
-
System ClassLoader
它也被稱為應(yīng)用程序類加載器(系統(tǒng)類加載器)(Application ClassLoader) ,與平臺類加載器不同。 系統(tǒng)類加載器通常用于定義應(yīng)用程序類路徑,模塊路徑和JDK特定工具上的類
負(fù)責(zé)在jvm啟動時(shí)加載來自java命令的class文件,以及classpath環(huán)境變量所指定的jar和類路徑
-
UserClass Loader
自定義類加載器
如果核心包中沒有項(xiàng)目所需要的jar,還有一個(gè)擴(kuò)展加載器:將擴(kuò)展的jar進(jìn)行加載
類加載器的繼承關(guān)系:System的父加載器為Platform,而Platform的父加載器為Bootstrap
反射
反射概述
JAVA反射機(jī)制是在運(yùn)行狀態(tài)中,對于任意一個(gè)類,都能夠知道這個(gè)類的所有屬性和方法;對于任意一個(gè)對象,都能夠調(diào)用它的任意方法和屬性;對于這種動態(tài)的獲取信息以及動態(tài)調(diào)用對象的方法的功能稱為:java語言的反射機(jī)制。文章來源:http://www.zghlxwxcb.cn/news/detail-664111.html
反射理解:
可以通過這個(gè)對象拿到字節(jié)碼文件,通過子節(jié)碼文件還原到類的本身(也就是說你拿到類的Class對象去使用這個(gè)類的成員方法,成員變量,構(gòu)造方法)文章來源地址http://www.zghlxwxcb.cn/news/detail-664111.html
獲取Class類對象的三種方式
- 類名.class屬性
- 對象名.getClass()方法
- Class.forName(全限定類名)方法
public class Person {
//私有成員變量
private String name;
//默認(rèn)成員變量
int age;
//公有成員變量
public String address;
//公有無參構(gòu)造方法
public Person() {
}
//私有的有參構(gòu)造方法 1個(gè)參數(shù)
private Person(String name) {
this.name = name;
}
//默認(rèn)的有參構(gòu)造方法 2個(gè)參數(shù)
Person(String name, int age) {
this.name = name;
this.age = age;
}
//公有的有參構(gòu)造方法 3個(gè)參數(shù)
public Person(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
//公有的無參無返回值方法
public void show() {
System.out.println("show");
}
//公有的有參無返回值方法
public void method(String s) {
System.out.println("method " + s);
}
//公有的有參有返回值方法
public String getString(String s, int i) {
return s + "---" + i;
}
//私有的無參無返回值方法
private void function(
到了這里,關(guān)于Java基礎(chǔ)篇——反射&枚舉的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!