反射是JAVA開發的高級特性,官方概念如下:
JAVA反射機制是在運行狀態中,對於任意一個實體類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意方法和屬性;這種動態獲取信息以及動態調用對象方法的功能稱爲java語言的反射機制。
其實就是,反射可以知道任意類或對象的屬性和方法,
比如,我建立了一個student類如下,內含公有,私有的屬性和方法:
package com.imooc.demo.entity;
public class Student {
public Integer id;
public Integer gender;
private String phoneNumber;
private String address;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getGender() {
return gender;
}
public void setGender(Integer gender) {
this.gender = gender;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Deprecated
private void print(String name) {
System.out.println(name);
}
}
然後再建立一個類,命名爲reflect類,以下代碼有4種方法獲取類的屬性和方法。
1.class.forname。可以直接在後面的括號里加上全限定名,用一個變量的泛型名稱接着,用這個studentClass來調用屬性或方法。
2.已經知道是哪個類,並且這個類就在本地代碼中,等號右邊直接用Student.class
3.new一個object類的對象,用這個對象來getclass。
4.用當前線程的類加載器,加載已知全限定名的類即可。
public class Reflact {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
// Class<?> studentClass = Class.forName("com.imooc.demo.entity.Student");
// Class<?> studentClass = Student.class;
// Object student = new Student();new
// Class<?> studentClass = student.getClass();
Class<?> studentClass = Thread.currentThread().getContextClassLoader().loadClass("com.imooc.demo.entity.Student");
獲得了studentclass,就可以調用它的方法了。
//獲取聲明過的所有方法,包括公有和私有的方法
Field[] declaredFields = studentClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField.getName());
}
//獲取該類和父類的公有方法。該方法和上述方法各有利弊
Field[] declaredFields = studentClass.getFields();
//可以調用私有方法
Method method = studentClass.getDeclaredMethod("print", String.class);
System.out.println(method.getReturnType());
//可以調用註解的方法。萬物皆對象,這裏的註解也可以認爲是對象。
Annotation[] annotations = method.getAnnotations();
// for (Annotation annotation : annotations) {
// System.out.println(annotation.toString());
//
// }
創建未知類的對象,並調用私有方法。
//用已經承接好的studentclass,創建一個新的對象,(用newinstance),
因爲此場景常用於框架,中間件等。不知道student類是否存在,所以此時不用new的方式,而是newinstance來創建對象。
並且invoke裏要填寫該私有方法的實參。如果現實該方法不可執行,我們可以用setAccessible來強制執行。
method.setAccessible(true);
method.invoke(studentClass.newInstance(),"xgx");
這些要用在什麼場景呢,比如單元測試,我們用mock儘量覆蓋所有的方法,但有些靜態方法,用普通的單元測試覆蓋不了,此時可以用反射來獲取方法。