今天在面試的時候遇到一個非常nice的面試官,當時問到了如何通過反射來獲取私有屬性,
雖然本人之前也有做過,不過今天面試官一問頓時一臉懵逼,於是打算寫這篇博客記錄下來。先來看下我們的javaBean
public class Test { private String name; private int age; private Test(int age){ this.age = age; } private void speak(String name){ System.out.println("我的名字是:"+name); } public Test(String name) { this.name = name; } }
首先,我們要了解三個反射包中的類:
Constructor:代表類的單個構造方法,通過Constructor我們可執行一個類的某個構造方法(有參或者無參)來創建對象時。
Method:代表類中的單個方法,可以用於執行類的某個普通方法,有參或無參,並可以接收返回值。
Field:代表類中的單個屬性,用於set或get屬性
AccessibleObject:以上三個類的父類,提供了構造方法,普通方法,和屬性的訪問控制的能力。
使用Class類中的方法可以獲得該類中的所有Constructor對象,Method對象,和Field對象。
但是任然無法訪問私有化的構造方法,普通方法,和私有屬性,此時我們可以使用他們繼承父類(AccessibleObject)中的
setAccessible()方法,來設置或取消訪問檢查,以達到訪問私有對象的目的。
Step1:獲取私有屬性
public static void main(String[] args) throws NoSuchFieldException { // TODO Auto-generated method stub /* * 使用反射來創建構造方法私有化的對象 * */ //1:獲取類的無參構造方法 Test test = new Test("張三"); Method[] methods = Test.class.getMethods(); Field[] fields = Test.class.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { fields[i].setAccessible(true); try { System.out.println(fields[i].get(test)); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(fields[i].getName()); } }然后,我們再來看一下輸出的:
張三
name
0
age
Step2:獲取私有方法
Method[] methods2 = Test.class.getDeclaredMethods(); for (int i = 0; i < methods2.length; i++) { methods2[i].setAccessible(true); System.out.println(methods2[i].getName()); }然后,我們再來看一下輸出的:
speak
Step3:調用私有方法
Test test = new Test("張三"); Method[] methods = Test.class.getDeclaredMethods(); for (int i = 0; i < methods.length; i++) { methods[i].setAccessible(true); try { methods[i].invoke(test,"成功調用"); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(methods[i].getName()); }
這樣,我們就獲得了私有屬性的值啦~~當然,凡事有利就有弊,然后我們再來說一下java反射的優缺點;
優點:
1:能夠運行時動態獲取類的實例,大大提高了系統的靈活性和擴展性;
2:與java動態編譯相結合,可以實現無比強大的功能。
缺點:
1:使用反射的性能較低;
2:使用反射來說相對不安全;
3:破壞了類的封裝性,可以通過反射來獲取這個類的屬性,和私有方法。