反射經(jīng)常聽(tīng)到這個(gè)詞械媒,但是總是不理解這個(gè)意思。今天便來(lái)理解一下反射這個(gè)概念评汰,為什么說(shuō)在框架設(shè)計(jì)中纷捞,反射用到的比較多。本文記錄一下學(xué)習(xí)反射方面的知識(shí)點(diǎn)被去。
反射概念
JAVA反射機(jī)制是在運(yùn)行狀態(tài)中主儡,對(duì)于任意一個(gè)類(lèi),都能夠知道這個(gè)類(lèi)的所有屬性和方法惨缆;對(duì)于任意一個(gè)對(duì)象糜值,都能夠調(diào)用它的任意一個(gè)方法和屬性;這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對(duì)象的方法的功能稱(chēng)為java語(yǔ)言的反射機(jī)制坯墨。概念比較精確寂汇、抽象但是不便于理解。譬如我們存在一個(gè)類(lèi)捣染,它的相關(guān)屬性骄瓣、方法、構(gòu)造器都是 private 類(lèi)型的耍攘,對(duì)于這樣一個(gè)類(lèi)榕栏,我們不能通過(guò) new 的方式來(lái)創(chuàng)建一個(gè)它的對(duì)象,更不能通過(guò)平常使用方法屬性的方式來(lái)調(diào)用這個(gè)類(lèi)的屬性少漆、方法臼膏,甚至來(lái)創(chuàng)建它的對(duì)象,但是通過(guò)反射這種方式卻可以生成它的對(duì)象以及調(diào)用它的屬性示损、方法渗磅。
Class
Class 與 class 有著本質(zhì)的區(qū)別。小寫(xiě)的 class 是 Java 中的關(guān)鍵字,而大寫(xiě)的 Class 則是類(lèi)始鱼。
public final class Class<T> implements java.io.Serializable,
GenericDeclaration,
Type,
AnnotatedElement {
}
在 Java 的世界里仔掸,一切皆是對(duì)象,在 Java 中存在兩種對(duì)象医清,一種是 new 產(chǎn)生的對(duì)象另一種則是 Class 對(duì)象起暮。一般的對(duì)象,我們可以通過(guò) new 關(guān)鍵字來(lái)產(chǎn)生会烙,而 Class 對(duì)象則不可以负懦,因?yàn)樗?JVM 生成用來(lái)保存對(duì)應(yīng)類(lèi)的信息的。也就是說(shuō)柏腻,如:當(dāng)我們定義了一個(gè)類(lèi) Person 時(shí)纸厉,編譯成功后,將會(huì)生成一個(gè) Person.class 字節(jié)碼五嫂,這個(gè)時(shí)候編譯器同時(shí)為我們從創(chuàng)建了一個(gè) Class 對(duì)象并將它保存在 Person.class 文件中颗品。也就是說(shuō):Person.java 編譯成 Person.class 后將會(huì)產(chǎn)生一個(gè)對(duì)應(yīng)的Class 對(duì)象。
Class 對(duì)象獲取
一般情況下沃缘,一個(gè)實(shí)例對(duì)象對(duì)應(yīng)的 Class 對(duì)象有以下三種方式獲惹唷:
1、通過(guò)實(shí)例變量的 getClass 方法:
Person person = new Person();
Class personClass = person.getClass();
System.out.println("class1: " + personClass);
2槐臀、直接給出對(duì)象類(lèi)文件的.class:
Class personClass1=Person.class;
System.out.println("class2: " + personClass1);
如果不能通過(guò) new 關(guān)鍵字來(lái)創(chuàng)建對(duì)象的話锄蹂,我們也可以通過(guò)第三種方式來(lái)獲取:
3峰档、通過(guò)類(lèi)Class的靜態(tài)方法forName():
try {
Class personClass2 = Class.forName("reflect.Person");
System.out.println("class3: " + personClass2);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
打印結(jié)果如下:
class1: class reflect.Person
class2: class reflect.Person
class3: class reflect.Person
Class 使用
JAVA反射機(jī)制是在運(yùn)行狀態(tài)中败匹,對(duì)于任意一個(gè)類(lèi),都能夠知道這個(gè)類(lèi)的所有屬性和方法讥巡;對(duì)于任意一個(gè)對(duì)象掀亩,都能夠調(diào)用它的任意一個(gè)方法和屬性;這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對(duì)象的方法的功能稱(chēng)為java語(yǔ)言的反射機(jī)制欢顷。
1槽棍、CLASS 名稱(chēng)獲取
對(duì)于 name 的獲取,Class 類(lèi)提供了三種方法:
Class.getName();
Class.getSimpleName();
Class.getCanonicalName();
那么這三種方式有何區(qū)別抬驴?通過(guò)具體的實(shí)例還說(shuō)明炼七。
首先我們得創(chuàng)建一個(gè)類(lèi) Person.java
package reflect;
public class Person {
private int age;
private String name;
public Person() {
}
public Person(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
然后分別獲取它的 Class 名稱(chēng):
//getName()方式
Person person = new Person();
Class personClass = person.getClass();
System.out.println("class1: " + personClass.getName());
//getSimpleName()方式
Class personClass1=Person.class;
System.out.println("class2: " + personClass1.getSimpleName());
//getCanonicalName()方式
try {
Class personClass2 = Class.forName("reflect.Person");
System.out.println("class3: " + personClass2.getCanonicalName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
打印結(jié)果如下:
class1: reflect.Person
class2: Person
class3: reflect.Person
可以看到第一種和第三種方式獲取的結(jié)果是一樣的,而只有第二種不一樣布持。及一三中獲取的是類(lèi)的完整路徑豌拙,而第二種獲取的是類(lèi)名,不包含包名题暖。而一三種有何區(qū)別可以通過(guò)類(lèi)的內(nèi)部類(lèi)來(lái)研究按傅。
2捉超、修飾符獲取
Java 中的修飾符主要有 private 、public 唯绍、static拼岳、protected、等况芒。Java 反射提供了 API 去獲取這些修飾符惜纸。
通過(guò) Class.getModifiers() 來(lái)獲取修飾符
Person person = new Person();
Class personClass = person.getClass();
System.out.println("modifiers: " + personClass.getModifiers());
結(jié)果如下:
modifiers: 1
返回的卻是一個(gè) int 型的數(shù)值。為什么會(huì)返回一個(gè)整型數(shù)值呢绝骚?這是因?yàn)橐粋€(gè)類(lèi)定義的時(shí)候可能會(huì)被多個(gè)修飾符修飾耐版,為了一并獲取,所以 Java 工程師考慮到了位運(yùn)算压汪,用一個(gè) int 數(shù)值來(lái)記錄所有的修飾符椭更,然后不同的位對(duì)應(yīng)不同的修飾符,這些修飾符對(duì)應(yīng)的位都定義在 Modifier 這個(gè)類(lèi)當(dāng)中蛾魄。
public class Modifier {
public static final int PUBLIC = 0x00000001;
public static final int PRIVATE = 0x00000002;
public static final int PROTECTED = 0x00000004;
public static final int STATIC = 0x00000008;
public static final int FINAL = 0x00000010;
......
public static String toString(int mod) {
StringBuilder sb = new StringBuilder();
int len;
if ((mod & PUBLIC) != 0) sb.append("public ");
if ((mod & PROTECTED) != 0) sb.append("protected ");
if ((mod & PRIVATE) != 0) sb.append("private ");
/* Canonical order */
if ((mod & ABSTRACT) != 0) sb.append("abstract ");
if ((mod & STATIC) != 0) sb.append("static ");
if ((mod & FINAL) != 0) sb.append("final ");
if ((mod & TRANSIENT) != 0) sb.append("transient ");
if ((mod & VOLATILE) != 0) sb.append("volatile ");
if ((mod & SYNCHRONIZED) != 0) sb.append("synchronized ");
if ((mod & NATIVE) != 0) sb.append("native ");
if ((mod & STRICT) != 0) sb.append("strictfp ");
if ((mod & INTERFACE) != 0) sb.append("interface ");
if ((len = sb.length()) > 0) /* trim trailing space */
return sb.toString().substring(0, len-1);
return "";
}
當(dāng)然如果需要打印字符串的話,可以通過(guò) Modifier 類(lèi)提供的靜態(tài)方法toString 來(lái)獲取湿滓。
System.out.println("modifiers: " + Modifier.toString(personClass.getModifiers()));
3滴须、獲取 CLASS 的成員
一個(gè)類(lèi)的成員包括屬性、方法叽奥、構(gòu)造函數(shù)扔水。對(duì)應(yīng)到 Class 中就是 Field、Method朝氓、Constructor魔市。接下來(lái)我們通過(guò)具體實(shí)例來(lái)熟悉如何獲取這些成員。
3.1赵哲、獲取 Field
獲取指定名稱(chēng)的屬性 API:
public Field getDeclaredField(String name)
throws NoSuchFieldException,
SecurityException;
public Field getField(String name)
throws NoSuchFieldException,
SecurityException
兩者的區(qū)別就是 getDeclaredField() 獲取的是 Class 中被 private 修飾的屬性待德。 getField() 方法獲取的是非私有屬性,并且 getField() 在當(dāng)前 Class 獲取不到時(shí)會(huì)向祖先類(lèi)獲取枫夺。
獲取所有的屬性将宪。
//獲取所有的屬性,但不包括從父類(lèi)繼承下來(lái)的屬性
public Field[] getDeclaredFields() throws SecurityException {}
//獲取自身的所有的 public 屬性橡庞,包括從父類(lèi)繼承下來(lái)的较坛。
public Field[] getFields() throws SecurityException {}
3.2、獲取 Method
Method 即是 Class 中的方法扒最。
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
public Method getMethod(String name, Class<?>... parameterTypes)
public Method[] getDeclaredMethods() throws SecurityException
public Method getMethod(String name, Class<?>... parameterTypes)
3.3丑勤、獲取 Constructor
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
public Constructor<T> getConstructor(Class<?>... parameterTypes)
public Constructor<?>[] getDeclaredConstructors() throws SecurityException
public Constructor<?>[] getConstructors() throws SecurityException
反射運(yùn)用
以上便是簡(jiǎn)單的獲取 Class 中的字段、方法吧趣、構(gòu)造函數(shù)法竞,反射的機(jī)制便是操控這些字段耙厚、方法、構(gòu)造函數(shù)爪喘。
關(guān)于作者
專(zhuān)注于 Android 開(kāi)發(fā)多年颜曾,喜歡寫(xiě) blog 記錄總結(jié)學(xué)習(xí)經(jīng)驗(yàn),blog 同步更新于本人的公眾號(hào)秉剑,歡迎大家關(guān)注泛豪,一起交流學(xué)習(xí)~