Java反射總結(jié)
1.反射機(jī)制的定義
1.1定義
Java反射機(jī)制是在運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)類帐我,都能夠知道這個(gè)類中的所有屬性和方法;對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意一個(gè)方法和屬性扒袖;這種動(dòng)態(tài)(運(yùn)行時(shí))獲取的信息以及動(dòng)態(tài)調(diào)用對(duì)象的方法的功能稱為java語(yǔ)言的反射機(jī)制。
1.2特點(diǎn)
- 優(yōu)點(diǎn):靈活性高亩码。因?yàn)榉瓷鋵儆趧?dòng)態(tài)編譯季率,即只有到運(yùn)行時(shí)才動(dòng)態(tài)創(chuàng)建 &獲取對(duì)象實(shí) 例
- 缺點(diǎn):效率低,反射執(zhí)行所需要的時(shí)間長(zhǎng)描沟。
2.反射的應(yīng)用場(chǎng)景
逆向代碼 飒泻,例如反編譯
與注解相結(jié)合的框架 例如Retrofit
單純的反射機(jī)制應(yīng)用框架 例如EventBus
動(dòng)態(tài)生成類框架 例如Gson
常用的動(dòng)態(tài)代理,工廠模式優(yōu)化吏廉,與注解結(jié)合使用都是值得我們學(xué)習(xí)的泞遗。
3.Java反射的功能
- 在運(yùn)行時(shí)判斷任意一個(gè)對(duì)象所屬的類。
2.在運(yùn)行時(shí)構(gòu)造任意一個(gè)類的對(duì)象席覆。
3.在運(yùn)行時(shí)判斷任意一個(gè)類所具有的成員變量和方法史辙。
4.在運(yùn)行時(shí)調(diào)用任意一個(gè)對(duì)象的方法。
5.生成動(dòng)態(tài)代理。
4.具體使用步驟
- 獲取 目標(biāo)類型的Class對(duì)象
- 通過(guò) Class 對(duì)象分別獲取Constructor類對(duì)象聊倔、Method類對(duì)象 & Field 類對(duì)象
- 通過(guò) Constructor類對(duì)象晦毙、Method類對(duì)象 & Field類對(duì)象分別獲取類的構(gòu)造函數(shù)、方法&屬性的具體信息耙蔑。
- . 通過(guò)Class對(duì)象創(chuàng)建類的對(duì)象
- 對(duì)新創(chuàng)建的對(duì)象屬性賦值见妒,調(diào)用相關(guān)方法。
4.1獲得Class對(duì)象
每個(gè)類被加載之后甸陌,系統(tǒng)就會(huì)為該類生成一個(gè)對(duì)應(yīng)的Class對(duì)象须揣。通過(guò)該Class對(duì)象就可以訪問(wèn)到JVM中的這個(gè)類。
在Java程序中獲得Class對(duì)象通常有如下三種方式:
使用Class類的forName(String clazzName)靜態(tài)方法钱豁。該方法需要傳入字符串參數(shù)返敬,該字符串參數(shù)的值是某個(gè)類的全限定名(必須添加完整包名)。
調(diào)用某個(gè)類的class屬性來(lái)獲取該類對(duì)應(yīng)的Class對(duì)象寥院。
調(diào)用某個(gè)對(duì)象的getClass()方法劲赠。該方法是java.lang.Object類中的一個(gè)方法。
//第一種方式 通過(guò)Class類的靜態(tài)方法——forName()來(lái)實(shí)現(xiàn)
class1 = Class.forName("com.demo.Person");
//第二種方式 通過(guò)類的class屬性
class1 = Person.class;
//第三種方式 通過(guò)對(duì)象getClass方法
Person person = new Person();
Class<?> class1 = person.getClass();
4.2獲取class對(duì)象的屬性秸谢、方法凛澎、構(gòu)造函數(shù)等
- 獲取class對(duì)象的成員變量
Field[] allFields = class1.getDeclaredFields();//獲取class對(duì)象的所有屬性
Field[] publicFields = class1.getFields();//獲取class對(duì)象的public屬性
Field ageField = class1.getDeclaredField("age");//獲取class指定屬性
Field desField = class1.getField("des");//獲取class指定的public屬性System.out.println(ageField);
// 輸出結(jié)果
private int com.demo.Person.age
- 獲取class對(duì)象的方法
Method[] methods = class1.getDeclaredMethods();//獲取class對(duì)象的所有聲明方法
Method[] allMethods = class1.getMethods();//獲取class對(duì)象的所有public方法 包括父類的方法
Method method = class1.getMethod("print", String.class);//返回次Class對(duì)象對(duì)應(yīng)類的、帶指定形參列表的public方法
Method declaredMethod = class1.getDeclaredMethod("print", String.class);//返回次Class對(duì)象對(duì)應(yīng)類的估蹄、帶指定形參列表的方法
// 輸出結(jié)果
public void com.demo.Person.print()
- 獲取class對(duì)象的構(gòu)造函數(shù)
Constructor<?>[] allConstructors = class1.getDeclaredConstructors();//獲取class對(duì)象的所有聲明構(gòu)造函數(shù)
Constructor<?>[] publicConstructors = class1.getConstructors();//獲取class對(duì)象public構(gòu)造函數(shù)
Constructor<?> constructor = class1.getDeclaredConstructor(String.class);//獲取指定聲明構(gòu)造函數(shù)
Constructor publicConstructor = class1.getConstructor(String.class);//獲取指定聲明的public構(gòu)造函數(shù)
4.訪問(wèn)權(quán)限問(wèn)題
反射機(jī)制的默認(rèn)行為受限于Java的訪問(wèn)控制,設(shè)置setAccessible
void setAccessible(boolean flag)
// 作用:為反射對(duì)象設(shè)置可訪問(wèn)標(biāo)志
// 規(guī)則:flag = true時(shí) 塑煎,表示已屏蔽Java語(yǔ)言的訪問(wèn)檢查,使得可以訪問(wèn) & 修改對(duì)象的私有屬性
boolean isAccessible()
// 返回反射對(duì)象的可訪問(wèn)標(biāo)志的值
static void setAccessible(AccessibleObject[] array, boolean flag)
// 設(shè)置對(duì)象數(shù)組可訪問(wèn)標(biāo)志
5.實(shí)例
1.定義Person類
public class Person implements Cloneable, Serializable {
private int age;
private String name;
public int number;
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;
}
public void print(){
System.out.println("Person類");
}
}
2.反射獲取對(duì)象的屬性臭蚁,方法
Class personClass1 = Person.class;
Field ageField = personClass1.getDeclaredField("age");//獲取class指定屬性
System.out.println(ageField);
Person person = (Person) personClass1.newInstance();
ageField.setAccessible(true);
ageField.set(person,2);
System.out.println(person.age);
//輸出結(jié)果
0
2
Method method = personClass1.getMethod("print");
method.setAccessible(true);
method.invoke(person);
6.總結(jié)
下面的流程圖為反射使用的流程最铁。本文只介紹的Java中的反射,后續(xù)將介紹注解垮兑,以后注解和反射在很多框架里面的使用冷尉。