首先,我們要了解三個反射包中的類:
Constructor:代表類的單個構造方法,通過Constructor我們可執行一個類的某個構造方法(有參或者無參)來創建對象時。
Method:代表類中的單個方法,可以用於執行類的某個普通方法,有參或無參,並可以接收返回值。
Field:代表類中的單個屬性,用於set或get屬性
AccessibleObject:以上三個類的父類,提供了構造方法,普通方法,和屬性的訪問控制的能力。
使用Class類中的方法可以獲得該類中的所有Constructor對象,Method對象,和Field對象。但是任然無法訪問私有化的構造方法,普通方法,和私有屬性,此時我們可以使用他們繼承父類(AccessibleObject)中的setAccessible()方法,來設置或取消訪問檢查,以達到訪問私有對象的目的。
我們來看下例子:
@Data
public class Demo {
public String name;
private String title;
}
public class Test {
public static void main(String[] args) {
try {
Class clazz = Class.forName("com.lian.demo.Demo");
Demo demo = (Demo) clazz.newInstance();
demo.setName("name1");
demo.setTitle("title1");
Field[] fields = clazz.getDeclaredFields();
Arrays.stream(fields).forEach(field -> {
try {
System.out.println("成員變量"+field.getName()+"的值爲:"+field.get(demo));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
執行結果如下
成員變量name的值爲:name1
java.lang.IllegalAccessException: Class com.lian.demo.Test can not access a member of class com.lian.demo.TestDemo with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
at java.lang.reflect.Field.get(Field.java:390)
at com.lian.demo.Test.lambda$main$0(Test.java:38)
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
at com.lian.demo.Test.main(Test.java:31)
說明反射機制中無法獲取到private成員的值。那到底有沒有辦法獲取到?當然是有。Java反射機制提供的setAccessible()方法可以取消Java的權限控制檢查。
Arrays.stream(fields).forEach(field -> {
boolean flag = field.isAccessible();
System.out.println(field.getName() + ":" + flag);
try {
//設置該屬性總是可訪問
field.setAccessible(true);
System.out.println("成員變量"+field.getName()+"的值爲:"+field.get(demo));
} catch (IllegalAccessException e) {
System.out.println(e.getMessage());
}
//還原可訪問權限
field.setAccessible(flag);
});
這下沒問題了,可以獲取到了。setAccessible(true)取消了Java的權限控制檢查,但不是改變方法或字段的訪問權限。而對於setAccessible()方法是否會破壞類的訪問規則,產生安全隱患,我在知乎上面看到的一篇回答貌似很有道理: