學(xué)習(xí)內(nèi)容:
- 傳統(tǒng)的 RTTI
- Class 對(duì)象的加載
- 獲取 Class 對(duì)象引用的方式
- ClassforName
- 類字面常量
- Class 引用的泛化
- instanceof 關(guān)鍵字
- 反射
- 相關(guān)類
- 簡(jiǎn)單使用示例
前言
運(yùn)行時(shí)類型信息使得我們可以在程序運(yùn)行時(shí)發(fā)現(xiàn)和使用類型信息霎肯,Java 中運(yùn)行時(shí)識(shí)別對(duì)象和類的信息有如下兩種方式:
- 傳統(tǒng)的 RTTI :假定我們?cè)诰幾g時(shí)已經(jīng)知道所有的類型
- 傳統(tǒng)的類型轉(zhuǎn)換观游。
- 通過查詢 Class 對(duì)象獲取運(yùn)行時(shí)所需的信息
- 通過 instanceof 得知對(duì)象是否是某個(gè)特定類型的實(shí)例
- 反射技術(shù):允許我們運(yùn)行時(shí)發(fā)現(xiàn)和使用類型的信息
1. RTTI
RTTI,Run-Time Type information
1.1 為什么需要 RTTI允跑?
面向?qū)ο缶幊讨谢镜哪康氖牵鹤尨a只操縱對(duì)基類的引用聋丝,這樣如果要添加一個(gè)新類來擴(kuò)展程序弱睦,就不會(huì)影響到原來的代碼渊额。
于是我們往往會(huì)創(chuàng)建一個(gè)具體對(duì)象端圈,之后將其向上轉(zhuǎn)型為基類型對(duì)象子库,并在后面使用該基類型對(duì)象引用仑嗅,但此時(shí)該對(duì)象已經(jīng)丟失了其具體類型仓技,我怎么調(diào)用具體類型的方法呢?此時(shí) RTTI 就起作用了阔逼。RTTI 會(huì)在運(yùn)行時(shí)嗜浮,識(shí)別一個(gè)對(duì)象的類型摩疑,得到引用指向的對(duì)象的確切類型雷袋。再之后就是多態(tài)的事情了,針對(duì)不同類型類型執(zhí)行不同代碼瓦灶。
1.2 Class 對(duì)象
Java 使用 Class 對(duì)象來執(zhí)行其 RTTI迫卢,那么 Class 對(duì)象是什么呢乾蛤?
類是程序的一部分家卖,每一個(gè)類都有一個(gè) Class 對(duì)象。換言之趴樱,每當(dāng)編寫并編譯了一個(gè)新類叁征,就會(huì)在同名的 .class 文件中產(chǎn)生一個(gè) Class 對(duì)象逛薇。Class 對(duì)象包含了與類有關(guān)的信息永罚。那創(chuàng)建 Class 對(duì)象具體做什么呢呢袱?答案是通過 Class 對(duì)象創(chuàng)建我們需要的關(guān)于這個(gè)類的所有對(duì)象(比如對(duì)象實(shí)例,或者靜態(tài)變量的引用值等)惕蹄。實(shí)際上焊唬,所有的類都是在對(duì)其第一次使用時(shí)赶促,動(dòng)態(tài)加載到 JVM 中的挟炬,其中,“類加載器” 會(huì)負(fù)責(zé)將 Class 對(duì)象加載到內(nèi)存中老速,而一旦加載成功之后橘券,他就可以用來創(chuàng)建這個(gè)類的所有對(duì)象繁成。
1.2.1 Class 對(duì)象的加載
前面我們提到過,所有的類都是在對(duì)其第一次使用時(shí)济似,動(dòng)態(tài)加載到 JVM 中的磺樱。實(shí)際上婆咸,當(dāng)創(chuàng)建第一個(gè)對(duì)類的靜態(tài)成員的引用時(shí)尚骄,就會(huì)加載這個(gè)類乖仇。這點(diǎn)也證明構(gòu)造器是類的靜態(tài)方法询兴,雖然其沒有顯式指明 static诗舰,即使用 new 操作符創(chuàng)建類的新對(duì)象也會(huì)被當(dāng)作對(duì)類的靜態(tài)成員的引用眶根。
因此,Java 程序在開始運(yùn)行之前并非被完全加載记劝,其各個(gè)部分在必需時(shí)才進(jìn)行加載厌丑。
當(dāng)使用該類時(shí)怒竿,類加載器首先會(huì)檢查這個(gè)類的 Class 對(duì)象是否已經(jīng)加載耕驰,如果尚未加載,默認(rèn)的類加載器就會(huì)根據(jù)類名查找 .class 文件饭弓,在這個(gè)類的字節(jié)碼被加載時(shí)示启,它們會(huì)接受驗(yàn)證夫嗓,以確保其沒有被破壞舍咖,并且不含不良 Java 代碼(這是 Java 安全防范的措施之一)锉桑。一旦某個(gè)類的 Class 對(duì)象被載入內(nèi)存民轴,那么它久被用來創(chuàng)建這個(gè)類的所有對(duì)象后裸。
補(bǔ)充一點(diǎn)關(guān)于類加載器:
- 類加載器子系統(tǒng)實(shí)際上可以包含一條類加載器鏈微驶,但是只有一個(gè)原生類加載器因苹,它是Java 實(shí)現(xiàn)的一部分,用來加載 可信類凶杖,包括 Java API 類官卡,通常是從本地盤中加載的寻咒。
- 如果有特殊需求(如以某種特殊的方式加載類毛秘,以支持 Web 服務(wù)器應(yīng)用)叫挟,那么可以掛接額外的類加載器抹恳,不過通常不需要添加額外的類加載器。
下面給出一個(gè)例子健霹,證明加載的時(shí)間點(diǎn):
class Candy {
static { System.out.println("Loading Candy"); }
}
class Gum {
static { System.out.println("Loading Gum"); }
}
class Cookie {
static { System.out.println("Loading Cookie"); }
}
public class SweetShop {
public static void print(Object obj) {
System.out.println(obj);
}
public static void main(String[] args) {
print("inside main");
new Candy();
print("After creating Candy");
try {
Class.forName("Gum");
} catch(ClassNotFoundException e) {
print("Couldn't find Gum");
}
print("After Class.forName(\"Gum\")");
new Cookie();
print("After creating Cookie");
}
}
/*輸出
inside main
Loading Candy
After creating Candy
Loading Gum
After Class.forName("Gum")
Loading Cookie
After creating Cookie
Process finished with exit code 0
*/
從結(jié)果上看糖埋,通過 new 創(chuàng)建 Candy 和 Cookie 的對(duì)象時(shí)瞳别,二者的 Class 對(duì)象被加載祟敛,也證明了 Class 對(duì)象僅在需要的時(shí)候才被加載垒棋。
比較特殊的一句代碼:
Class.forName("Gum")
其中 forName 是 Class 類(所有 Class 對(duì)象都屬于這個(gè)類)的一個(gè) static 成員,是取得 Class 對(duì)象的引用的一種方法衣撬。此處并未使用獲取返回的 Class 對(duì)象引用具练,它的作用在于要求 JVM 查找并加載類,加載的過程中甜无,Gum 的 static 子句被執(zhí)行扛点,Gum 類即被加載哥遮。
Class 對(duì)象和其他對(duì)象一樣,我們可以獲取并操作它的引用
1.2.2 獲取 Class 對(duì)象的引用
無論何時(shí)陵究,只要我們想在運(yùn)行時(shí)使用類型信息眠饮,就必須首先獲得對(duì)恰當(dāng)?shù)?Class 對(duì)象的引用。本小節(jié)就來介紹一下三種獲取 Class 對(duì)象引用的方式铜邮,及其要點(diǎn)。
1.2.2.1 Class.forName()
forName() 是取得 Class 對(duì)象的引用的一種方法松蒜。它接收一個(gè)包含目標(biāo)類的文本名的 String 作為輸入?yún)?shù)扔茅,返回一個(gè)和 Class 對(duì)象的引用。
該方法會(huì)要求 JVM 查找并加載指定的類秸苗,然后 JVM 會(huì)執(zhí)行靜態(tài)代碼段召娜,之后返回 Class 對(duì)象的引用
如果 Class.forName 找不到要加載的類,會(huì)配出 ClassNotFoundException 異常惊楼。
Class.forName 的優(yōu)勢(shì):
- 不需要為了獲得 Class 引用而持有該類型的對(duì)象玖瘸。
- 當(dāng)然,如果已經(jīng)持有對(duì)象胁后,那么就可以通過 getClass() 方法來獲取 Class 引用店读,這個(gè)方法屬于跟類 Object 的一部分,返回表示該對(duì)象的實(shí)際類型的 Class 引用攀芯。
public static void main(String[] args) {
Class c = null;
try{
//通過Class.forName獲取Gum類的Class對(duì)象
c = Class.forName("Gum");
System.out.println(c.getName());
}catch (ClassNotFoundException e){
e.printStackTrace();
}
//通過實(shí)例對(duì)象獲取Gum的Class對(duì)象
Gum gum = new Gum();
Class c2=gum.getClass();
}
關(guān)于 Class 的其他方法屯断,詳見 https://docs.oracle.com/javase/9/docs/api/java/lang/Class.html
1.2.2.2 類字面常量
Java 還提供了另一種方法來生產(chǎn)對(duì) Class 對(duì)象的引用,即使用類字面常量侣诺,如下:
Class c = Gum.class;
該方式更簡(jiǎn)單殖演,更安全,因?yàn)榫幾g時(shí)會(huì)受到檢查年鸳,因此不需要放在 try 語句塊中趴久,同時(shí)根除了 forName() 方法的調(diào)用,所以更高效搔确。
更加實(shí)用的是類字面常量不僅僅你可以用于普通的類彼棍,也可以應(yīng)用于接口、數(shù)組以及基本數(shù)據(jù)類型膳算。對(duì)于基本數(shù)據(jù)類型的包裝其類座硕,還有一個(gè)標(biāo)準(zhǔn)字段 TYPE。TYPE 字段是一個(gè)引用涕蜂,指向?qū)?yīng)的基本數(shù)據(jù)類型的 Class 對(duì)象华匾,等價(jià)關(guān)系如下所示:
boolean.class == Boolean.TYPE;
char.class == Character.TYPE;
byte.class == Byte.TYPE;
short.class == Short.TYPE;
int.class == Integer.TYPE;
long.class == Long.TYPE;
float.class == Float.TYPE;
double.class == Double.TYPE;
void.class == Void.TYPE;
需要注意的是:此方式 .class 創(chuàng)建對(duì) Class 對(duì)象得到引用是,不會(huì)自動(dòng)初始化該 Class 對(duì)象机隙,加載的過程如下:
- 加載:由類加載器執(zhí)行蜘拉。該步驟將查找字節(jié)碼萨西,并從這些字節(jié)碼中創(chuàng)建一個(gè) Class 對(duì)象
- 鏈接:在鏈接階段將驗(yàn)證類中的字節(jié)碼,為靜態(tài)域分配存儲(chǔ)空間旭旭,并且如果必須的話谎脯,將解析這個(gè)類創(chuàng)建的對(duì)其它類的所有引用。
- 初始化:如果該類具有超類您机,則對(duì)其初始化穿肄,執(zhí)行靜態(tài)初始化器和靜態(tài)初始化塊。
也就是說际看,初始化被延遲到了對(duì)靜態(tài)方法或者非常數(shù)靜態(tài)域進(jìn)行首次引用時(shí)才執(zhí)行咸产,如下:
import java.util.*;
class Initable {
//編譯期靜態(tài)常量
static final int staticFinal = 47;
//非編期靜態(tài)常量
static final int staticFinal2 =
ClassInitialization.rand.nextInt(1000);
static {
System.out.println("Initializing Initable");
}
}
class Initable2 {
//靜態(tài)成員變量
static int staticNonFinal = 147;
static {
System.out.println("Initializing Initable2");
}
}
class Initable3 {
//靜態(tài)成員變量
static int staticNonFinal = 74;
static {
System.out.println("Initializing Initable3");
}
}
public class ClassInitialization {
public static Random rand = new Random(47);
public static void main(String[] args) throws Exception {
//字面常量獲取方式獲取Class對(duì)象
Class initable = Initable.class;
System.out.println("After creating Initable ref");
//不觸發(fā)類初始化
System.out.println(Initable.staticFinal);
//會(huì)觸發(fā)類初始化
System.out.println(Initable.staticFinal2);
//會(huì)觸發(fā)類初始化
System.out.println(Initable2.staticNonFinal);
//forName方法獲取Class對(duì)象
Class initable3 = Class.forName("Initable3");
System.out.println("After creating Initable3 ref");
System.out.println(Initable3.staticNonFinal);
}
}
/*結(jié)果
After creating Initable ref
47
Initializing Initable
258
Initializing Initable2
147
Initializing Initable3
After creating Initable3 ref
74
/*
*/
如果一個(gè) static final 值是編譯期常量,就像 Initable.staticFinal仲闽,那么這個(gè)值不需要對(duì) Initable 類進(jìn)行初始化就可以被讀取脑溢。但這并不是說 static final 就能保證這一點(diǎn),譬如Initable.staticFinal2 就需要進(jìn)行類的初始化赖欣,因?yàn)樗皇蔷幾g期常量屑彻。
如果一個(gè) static 域不是 final 的,那么訪問錢顶吮,需要先進(jìn)性鏈接(分配空間)和初始化(初始化存儲(chǔ)空間)社牲。
1.2.3 Class 引用的泛化
Class 引用總是指向某個(gè) Class 對(duì)象,它可以制造類的實(shí)例悴了,并包含可作用于這些實(shí)例的所有方法代碼搏恤。因此,Class 引用表示的是其指向的對(duì)象的確切類型湃交。
Java SE5 引入泛型后熟空,可以通過泛型來對(duì) Class 對(duì)象的類型進(jìn)行限定使得 Class 對(duì)象類型更為具體。
public class GenericClassReferences {
public static void main(String[] args){
Class intClass = int.class;
Class<Integer> genericIntClass = int.class;
genericIntClass = Integer.class;
//沒有泛型的約束,可以隨意賦值
intClass= double.class;
//編譯期錯(cuò)誤,無法編譯通過
//genericIntClass = double.class
}
}
普通的類引用不會(huì)產(chǎn)生警告信息搞莺;而通過泛型語法息罗,可以讓編譯器強(qiáng)制執(zhí)行額外的類型檢查,使得泛型類引用只能賦值為指向其聲明的類型才沧,在編譯期就能發(fā)現(xiàn)這種錯(cuò)誤迈喉。
如下的語句看起來是正確的,但是實(shí)際上無法工作温圆。
Class<Number> genericNumberClass=Integer.class;
無法正常工作的原因在于 Integer Class 對(duì)象不是 Number Class 對(duì)象的子類(盡管 Integer 繼承自 Number)挨摸。
為了適用泛化的 Class 引用是放松限制,適用通配符 "?"捌木,其表示任何"事物":
Class<?> intClass = int.class;
intClass = double.class;
上述代碼是可行的,實(shí)際上Class<?> 優(yōu)于普通的 Class嫉戚,因?yàn)槠胀ǖ?Class 不會(huì)產(chǎn)生編譯器警告信息刨裆,CLass<?> 的好處在于它表示你并非是碰巧或者由于疏忽使用了一個(gè)非具體的類引用澈圈,而是你正是選擇了非具體的版本。
如果我們需要限定 Class 為某種類型或者該類型的任何子類型帆啃,那么需要將 ? 和 extends 配合適用瞬女,創(chuàng)建一個(gè)范圍:
Class<? extends Number> bounded = Integer.class;
//賦予其他類型
bounded = double.class;
bounded = number.class;
上述代碼同樣可行,向 Class 添加泛型語法原因僅僅是為了提供編譯期類型檢查努潘。
1.2.4 Class 的類型轉(zhuǎn)換
Java SE5 中添加了用于 Class 引用的轉(zhuǎn)型語法诽偷,即 cast() 方法:
class Building {}
class House extends Building {}
public class ClassCasts {
public static void main(String[] args){
//通過 cast()
Building b= new House();
Class<House> houseType = House.class;
House h = houseType.cast(b);
//直接強(qiáng)制轉(zhuǎn)換
h = (House)b;
}
}
1.2.5 instanceof 關(guān)鍵字
關(guān)于 instanceof 關(guān)鍵字,用于判斷對(duì)象是不是某個(gè)特定類型的實(shí)例疯坤,返回布爾值
if(x instanceof Dog){
Dog dog = (Dog)x;
}
在將下轉(zhuǎn)型為 Dog 之前报慕,利用 instanceof 判斷 x 是不是 Dog 類型的實(shí)例,如果返回 true 在進(jìn)行類型轉(zhuǎn)換压怠。
1.2.5.1 instanceof 關(guān)鍵字與 isInstance 方法
isInstance 方法是 Class 類中的方法眠冈,也是用來判斷對(duì)象類型的,二者效果相同菌瘫∥贤纾可以說二者是動(dòng)態(tài)等價(jià)的。
來對(duì)比一下二者的用法:
obj.instanceof(class)雨让,判斷對(duì)象是不是這種類型
- 一個(gè)對(duì)象是本身類的一個(gè)對(duì)象
- 一個(gè)對(duì)象是本身類父類(父類的父類)和接口(接口的接口)的一個(gè)對(duì)象
- 所有對(duì)象都是Object
- 凡是null有關(guān)的都是false null.instanceof(class)
class.inInstance(obj)雇盖,判斷對(duì)象能不能被轉(zhuǎn)化為這個(gè)類
- 這個(gè)對(duì)象是本身類的一個(gè)對(duì)象
- 一個(gè)對(duì)象能被轉(zhuǎn)化為本身類所繼承類(父類的父類等)和實(shí)現(xiàn)的接口(接口的父接口)強(qiáng)轉(zhuǎn)
- 所有對(duì)象都能被Object的強(qiáng)轉(zhuǎn)
- 凡是null有關(guān)的都是false(class.inInstance(null))
同時(shí)對(duì)于檢查 Class 對(duì)象是否相等時(shí),”==“ 和 equals() 方法也是一樣的栖忠。
例子如下:
class A {}
class B extends A {}
public class C {
static void test(Object x) {
print("Testing x of type " + x.getClass());
print("x instanceof A " + (x instanceof A));
print("x instanceof B " + (x instanceof B));
print("A.isInstance(x) " + A.class.isInstance(x));
print("B.isInstance(x) " +
B.class.isInstance(x));
print("x.getClass() == A.class " +
(x.getClass() == A.class));
print("x.getClass() == B.class " +
(x.getClass() == B.class));
print("x.getClass().equals(A.class)) " +
(x.getClass().equals(A.class)));
print("x.getClass().equals(B.class)) " +
(x.getClass().equals(B.class)));
}
public static void main(String[] args) {
test(new A());
test(new B());
}
}
/*輸出
Testing x of type class com.zejian.A
x instanceof A true
x instanceof B false //父類不一定是子類的某個(gè)類型
A.isInstance(x) true
B.isInstance(x) false
x.getClass() == A.class true
x.getClass() == B.class false
x.getClass().equals(A.class)) true
x.getClass().equals(B.class)) false
---------------------------------------------
Testing x of type class com.zejian.B
x instanceof A true
x instanceof B true
A.isInstance(x) true
B.isInstance(x) true
x.getClass() == A.class false
x.getClass() == B.class true
x.getClass().equals(A.class)) false
x.getClass().equals(B.class)) true
*/
2. 反射
2.1 基礎(chǔ)知識(shí)
在Java中的反射機(jī)制是指在運(yùn)行狀態(tài)中崔挖,對(duì)于任意一個(gè)類都能夠知道這個(gè)類所有的屬性和方法;并且對(duì)于任意一個(gè)對(duì)象娃闲,都能夠調(diào)用它的任意一個(gè)方法虚汛;這種動(dòng)態(tài)獲取信息以及動(dòng)態(tài)調(diào)用對(duì)象方法的功能成為Java語言的反射機(jī)制。
前面我們提到過皇帮,RTTI 有限制:所有類型必須在編譯時(shí)已知卷哩,這樣才能通過 RTTI 識(shí)別。換句話說属拾,編譯時(shí)将谊,編譯器必須知道所有要通過 RTTI 處理的類。
而反射也是有限制的:目標(biāo)對(duì)象的類對(duì)應(yīng)的 .class 文件必須可獲取渐白。
當(dāng)通過反射與一個(gè)位置類型的對(duì)象打交道時(shí)尊浓,JVM 只是簡(jiǎn)單的檢車這個(gè)對(duì)象,看它屬于哪個(gè)特定的類(就像 RTTI 那樣)纯衍。在用它做其他事情之前栋齿,必須先加載那個(gè)類的 Class 對(duì)象。
因此,RTTI 和 反射之間真正的區(qū)別只在于:
- 對(duì)于 RTTI瓦堵,編譯器在編譯期間打開和檢查 .class 文件
- 對(duì)于反射機(jī)制基协,.class 文件在編譯期間是不可獲取的,所以在運(yùn)行時(shí)打開和檢查 .class 文件菇用。
2.2 類庫(kù)的支持
Class 類與 java.lang.reflect 類庫(kù)一起對(duì)反射的概念進(jìn)行了支持澜驮,該類庫(kù)包含了 Field、Method 以及 Constructor 類(每個(gè)類都是先了 member 接口)惋鸥。這些類型的對(duì)象是由 JVM 在運(yùn)行時(shí)創(chuàng)建的杂穷,用以表示未知類里對(duì)應(yīng)的成員。
Class 類:反射的核心類卦绣,可以獲取類的屬性耐量、方法等信息
Constructor 類:表示類的構(gòu)造方法,利用它可以在運(yùn)行時(shí)動(dòng)態(tài)創(chuàng)建對(duì)象
Field 類:表示類的成員變量迎卤,通過它可以在運(yùn)行時(shí)動(dòng)態(tài)修改成員變量的屬性值(包含private)
Method 類:表示類的成員方法拴鸵,通過它可以動(dòng)態(tài)調(diào)用對(duì)象的方法(包含private)
相關(guān) API,見 https://docs.oracle.com/javase/9/docs/api/overview-summary.html
2.3 反射的使用示例
使用反射蜗搔,由三個(gè)步驟
- 獲取 Class 對(duì)象
- 獲取 Class 類中的信息
- 使用反射的相關(guān) API 做具體操作
假定目標(biāo)類如下:
package com.whdalive.reflection;
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//getter和setter方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String toString(){
return "姓名:"+name+" 年齡:"+age;
}
}
步驟1. 獲取 Class 對(duì)象
三種方式:(具體解釋 ↑)
Class c = e.getClass();
Class c = Example.class;
Class c = Class.forName("類的全路徑");
示例:
Class c = Class.forName("reflection.Person");
步驟2. 獲取 Class 類中的信息
package com.whdalive.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
showInfo();
}
private static void showInfo() {
try {
//獲取Person類的Class對(duì)象
Class clazz=Class.forName("com.whdalive.reflection.Person");
//獲取Person類的所有方法信息
Method[] method=clazz.getDeclaredMethods();
for(Method m:method){
System.out.println(m.toString());
}
//獲取Person類的所有成員屬性信息
Field[] field=clazz.getDeclaredFields();
for(Field f:field){
System.out.println(f.toString());
}
//獲取Person類的所有構(gòu)造方法信息
Constructor[] constructor=clazz.getDeclaredConstructors();
for(Constructor c:constructor){
System.out.println(c.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/*輸出
public java.lang.String com.whdalive.reflection.Person.toString()
public java.lang.String com.whdalive.reflection.Person.getName()
public void com.whdalive.reflection.Person.setName(java.lang.String)
public void com.whdalive.reflection.Person.setAge(int)
public int com.whdalive.reflection.Person.getAge()
private java.lang.String com.whdalive.reflection.Person.name
private int com.whdalive.reflection.Person.age
public com.whdalive.reflection.Person()
public com.whdalive.reflection.Person(java.lang.String,int)
*/
步驟3. 使用反射的相關(guān) API 做具體操作
這里只展示創(chuàng)建一個(gè) Person 對(duì)象劲藐,并將其初始化。
package com.whdalive.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
create();
}
private static void create() {
try {
//獲取Person類的Class對(duì)象
Class clazz=Class.forName("com.whdalive.reflection.Person");
/**
* 第一種方法創(chuàng)建對(duì)象
*/
//創(chuàng)建對(duì)象
Person p=(Person) clazz.newInstance();
//設(shè)置屬性
p.setName("張三");
p.setAge(16);
System.out.println(p.toString());
/**
* 第二種方法創(chuàng)建
*/
//獲取構(gòu)造方法
Constructor c=clazz.getDeclaredConstructor(String.class,int.class);
//創(chuàng)建對(duì)象并設(shè)置屬性
Person p1=(Person) c.newInstance("李四",20);
System.out.println(p1.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
/*輸出
姓名:張三 年齡:16
姓名:李四 年齡:20
*/
以上即為 反射的簡(jiǎn)單介紹樟凄。也許日后我會(huì)再深入分析反射的應(yīng)用場(chǎng)景聘芜。hhh
全文完,共勉缝龄。