一溉愁、反射
- java反射機(jī)制:在運(yùn)行狀態(tài)中屋摇,對于任意一個類揩魂,都能夠知道這個類的所有屬性和方法;對于任意一個對象炮温,都能夠調(diào)用它的任意一個方法和屬性火脉,這種動態(tài)獲取的信息以及動態(tài)調(diào)用對象的方法的功能稱為java語言的反射機(jī)制。
- 反射就是把java類的各種成分映射成一個個java對象。
要想解剖一個類倦挂,必須先要獲取該類的字節(jié)碼文件對象畸颅;而解剖使用的就是Class類中的方法,所以先要獲取到每一個字節(jié)碼文件對應(yīng)的Class類型的對象方援。 -
一個類有:成員變量没炒、方法、構(gòu)造方法犯戏、包等信息送火,利用反射技術(shù)可以對一個類進(jìn)行解剖。把各個組成部分映射成一個個對象先匪。
Class對象的由來是將class文件讀入內(nèi)存种吸,并為之創(chuàng)建一個class對象。
二呀非、反射的理解
1.正射
一般情況下坚俗,我們使用某個類時必定知道它是什么類,是用來干什么的姜钳。于是我們直接對這個類進(jìn)行實(shí)例化坦冠,之后使用這個類對象進(jìn)行操作。
User user = new User(); //直接初始化哥桥,正射
user.setAge(20);
2. 反射
反射則是一開始并不知道我們要初始化的類對象是什么辙浑,自然無法使用new關(guān)鍵字來創(chuàng)建對象。
反射就是在運(yùn)行時才知道要操作的類是什么拟糕,并且可以運(yùn)行時獲取類的完整構(gòu)造判呕,并調(diào)用對應(yīng)的方法。
@Test
public void test02() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//獲取類的Class對象
Class c1 = Class.forName("demo01.User");
//根據(jù) Class對象 實(shí)例獲取 Constructor對象
Constructor constructor = c1.getConstructor();
//根據(jù) Constructor對象 的 newInstance方法 獲取反射類對象
Object o = constructor.newInstance();
//獲取方法的 Method對象
Method setAgeMethod = c1.getMethod("setAge", Integer.class);
//利用 invoke方法 調(diào)用方法
setAgeMethod.invoke(o,13);
Method getAge = c1.getMethod("getAge");
System.out.println(getAge.invoke(o));
}
三送滞、反射的常用API
1.獲取反射中的Class對象
- 使用Class.forName靜態(tài)方法侠草。當(dāng)我們知道某類的全路徑名時,可以使用此方法獲取Class類對象犁嗅。用的最多边涕,但可能拋出 ClassNotFoundException 異常。
Class c1 = Class.forName("java.lang.String");
- 直接通過 類名.class 的方式得到褂微,該方法最為安全可靠功蜓,程序性能更高。這說明任何一個類都有一個隱含的靜態(tài)成員變量class宠蚂。這種方法只適合在編譯前就知道操作的class式撼。
Class c2 = String.class;
- 通過對象調(diào)用 getClass() 方法來獲取,通常應(yīng)用在:比如你傳過來一個 Object 類型的對象求厕,而我不知道你具體是什么類著隆,用這種方法扰楼。
String str = new String("Hello");
Class c3 = str.getClass();
需要注意的是:一個類在 JVM 中只會有一個 Class 實(shí)例,即我們對上面獲取的 c1美浦、c2和c3進(jìn)行 equals 比較弦赖,發(fā)現(xiàn)都是true。
2. 通過反射創(chuàng)建類對象
- 通過 Class對象 的newInstance()方法
Class c1 = User.class;
User user = (User)c1.newInstance();
- 通過 Constructor對象 的newInstance()方法
Class c1 = User.class;
Constructor constructor = c1.getConstructor();
User user = (User)constructor.newInstance();
通過 Constructor 對象創(chuàng)建類對象可以選擇特定構(gòu)造方法抵代,而通過 Class 對象則只能使用默認(rèn)的無參數(shù)構(gòu)造方法腾节。下面的代碼就調(diào)用了一個有參數(shù)的構(gòu)造方法進(jìn)行了類對象的初始化。
Class c1 = User.class;
Constructor constructor = c1.getConstructor(String.class,Integet.class);
User user = (User)constructor.newInstance("aaa",12);
3.通過反射獲取類屬性荤牍、方法案腺、構(gòu)造器
- 我們通過 Class 對象的 getFields() 方法可以獲取 Class 類的屬性,但無法獲取私有屬性康吵。
Class clz = Phone.class;
Field[] fields = clz.getFields();
for (Field field : fields) {
System.out.println(field.getName());
}
輸出的結(jié)果是:
price
- 如果使用 Class 對象的 getDeclaredFields() 方法則可以獲取包括私有屬性在內(nèi)的所有屬性
Class clz = Phone.class;
Field[] fields = clz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName());
}
輸出結(jié)果是:
name
price
四劈榨、使用反射函數(shù)的例子
反射就是把java類中的各種成分映射成一個個對象
User.java
public class User {
private String username;
public void sayHi(String words){
System.out.println(username+":"+words);
}
private String sayHello(String tag){
return tag;
}
}
ReflectDemo.java
public class ReflectDemo {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
Class<?> aClass = Class.forName("com.msj.reflect.User");
System.out.println(aClass.getName());
User user = (User)aClass.newInstance();
// 私有方法
Method sayHello = aClass.getDeclaredMethod("sayHello", String.class);
//訪問私有方法、屬性都要設(shè)置setAccessible(true)
sayHello.setAccessible(true);
Object aaa = sayHello.invoke(user, "aaa");
System.out.println(aaa);
// 公有方法
Method sayHi = aClass.getMethod("sayHi", String.class);
sayHi.invoke(user, "bbb");
// 私有屬性
Field username = aClass.getDeclaredField("username");
username.setAccessible(true);
username.set(user,"msj");
sayHi.invoke(user,"bbb");
}
}
五晦嵌、new 對象和反射得到對象的區(qū)別
- 在使用反射的時候同辣,必須確保這個類已經(jīng)加載并已經(jīng)連接了。使用new的時候惭载,這個類可以沒有被加載旱函,也可以已經(jīng)被加載。
- new關(guān)鍵字可以調(diào)用任何public構(gòu)造方法描滔,而反射只能調(diào)用無參構(gòu)造方法棒妨。
- new關(guān)鍵字是強(qiáng)類型的,效率相對較高含长。反射是弱類型的券腔,效率較低。
- 反射提供了一種更加靈活的方式創(chuàng)建對象拘泞,得到對象的信息纷纫。如Spring中AOP等的使用,動態(tài)代理的使用陪腌,都是基于反射的辱魁。