Java反射機制,通過物件訪問呼叫類的私有成員屬性或者方法
阿新 • • 發佈:2019-02-08
Java反射機制原理
Java中萬物皆物件,類class也是物件,是一個名為Class的類的物件。
所以就可以通過這個Class類型別的物件class,用物件訪問類的屬性和方法。
Class是對類的抽象(每個類對應一份位元組碼)。一般情況下,比如A a = new A();
直接通過a物件呼叫方法即可。但是在有些場景下,這樣是做不到的,
比如類名A是通過引數傳遞過來的,這時候你就無法通過new的方法建立物件,需要先載入這個類,
獲取Method物件,然後用Method已反射的形式呼叫相應的方法。
如何獲得Class的類型別
先宣告一個類text的物件t;
text1 t = new text1();
有三種方式可以來獲得類型別:
Class t0 = text.class;//通過類獲得類型別,說明Class類中隱含著一個class的物件
Class t1 = t.getClass();//通過物件獲得類型別
Class t2 = null;
text t4 = null;
try {
t2 = Class.forName("classReflex.text");// 通過類的全名獲得類型別
t4 = (text) t0.newInstance();// 通過類型別獲得類的物件
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
進入正題:通過類型別來實現對類的成員變數、方法、構造方法的訪問和呼叫。
首先是一個類text1
public class text1 {
public int x;
protected boolean b;
private String s;
public text1() {
// TODO Auto-generated constructor stub
}
public void f0() {
System.out.println("我愛計算機!我愛Android!");
}
private void f0_private() {
System.out.println("就算我是私有的方法!我愛計算機!我愛Android!");
}
public void f1(int i, String s1, boolean b) {
}
public int f2(int i, int s1, int b) {
return i;
}
public String f3(String i, String s1, String b) {
return i;
}
}
利用物件獲得類的成員變數
- 利用物件獲得類型別Class c = object.getClass();
- 通過getName()方法獲得類的名稱。
- getDeclaredFields()會返回類自己定義的所有的成員屬性的Field集合,(領域)
- 通過Class type = field.getType();獲得屬性的類型別,getName()就能得到屬性的具體型別了
- 關於屬性的呼叫類似於下文的方法的呼叫
public static void printClassAttribute(Object object) {
// 首先獲得類的資訊,先獲得類的型別。
Class c = object.getClass();
// 獲得類的名字,傳入的是什麼型別,就表示什麼型別,而不是父類object型別。
System.out.println("類的名稱:" + c.getName());
System.out.println("類的成員屬性:");
Field[] Fields = c.getDeclaredFields();
if (Fields.length > 0) {
for (Field field : Fields) {
Class type = field.getType();
System.out.println("field.getName()-->" + field.getName());
System.out
.println(field.getModifiers() + " " + type.getSimpleName() +
" m" + type.getSimpleName() + ";");
}
} else {
System.out.println("沒有成員屬性");
}
}
利用物件獲得類的成員方法
通過類型別物件訪問類所有的方法
- c.getDeclaredMethods();通過類型別的物件獲得方法類的物件集合Method的集合。
- 通過Method物件的getReturnType()獲得方法的返回型別的類型別物件
- 同股票method.getParameterTypes()獲得方法的輸入形參的類型別集合。之後就好辦啦,通過類型別得到型別。
通過類型別物件呼叫類的方法
- Methodm m= c.getMethod(“方法名”, 形參的類型別集合);獲得指定方法的物件
- 如果該方法是私有方法需要現宣告該方法訪問無障礙setAccessible(true);
- 之後呼叫m.invoke(c.newInstance,”實參”集合);呼叫類的方法。
- 當然如果是靜態方法就不需要傳入型別物件,只需要傳入類型別物件c就可以了
public static void printClassMethod(Object object) {
// 首先獲得類的資訊,先獲得類的型別。
Class c = object.getClass();
// 獲得類的名字,傳入的是什麼型別,就表示什麼型別,而不是父類object型別。
System.out.println("類的名稱:" + c.getName());
System.out.println("類的成員方法:");
/*
* Method型別是方法的型別。即:方法也是物件,是型別Method的物件
* getMethods()獲得類的所有成員方法,包括從父類繼承來的方法
* getDeclaredMethods()獲得類自己定義的成員方法。不包含父類的方法
*/
// Method[] methods = c.getMethods();
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
// 獲得方法的返回值的類型別
Class returnTyoe = method.getReturnType();
System.out.print(returnTyoe.getSimpleName() + " " + method.getName() + "(");
// 獲得方法所有的形引數組
Class[] parameterTypes = method.getParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
Class parameterType = parameterTypes[i];
if (i != 0)
System.out.print(" , ");
System.out.print(parameterType.getSimpleName() + " par" + i);
}
System.out.println(");");
}
System.out.println("methods.length-->" + methods.length);
/**
* 利用反射呼叫public方法f0();<br/>
* 先獲得方法的物件Method型別的,由方法物件呼叫物件的方法
*/
Method m;
try {
m = c.getMethod("f0", null);
m.invoke(c.newInstance(), null);// 通過類的物件呼叫物件的方法,後面的是引數
// 如果的呼叫靜態方法,就不必傳入類的物件了,而只需要傳遞類型別就可以了m.invoke(c, null);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException |
IllegalArgumentException
| InvocationTargetException | InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/**
* 利用反射呼叫private方法f0(); <br/>
* m_private.setAccessible(true);//訪問私有方法的關鍵步驟,設定為訪問無障礙
*/
Method m_private;
try {
m_private = c.getDeclaredMethod("f0_private", null);
m_private.setAccessible(true);// 訪問私有方法的關鍵步驟,設定為訪問無障礙,但是也只能訪問該類型別能訪問到的方法,子類就無法訪問父類的私用方法
m_private.invoke(c.newInstance(), null);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException |
IllegalArgumentException| InvocationTargetException | InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
利用物件獲得類的構造方法
和呼叫成員方法類似,不再做過多講解。
public static void printStructureMethod(Object object) {
Class c = object.getClass();
// 獲得類的名字,傳入的是什麼型別,就表示什麼型別,而不是父類object型別。
System.out.println("類的名稱:" + c.getName());
System.out.println("類的構造方法:");
Constructor[] constructors = c.getConstructors();
for (int i = 0; i < constructors.length; i++) {
Constructor constructor = constructors[i];
System.out.print(constructor.getName() + " (");
Class[] parameterTypes = constructor.getParameterTypes();
for (int j = 0; j < parameterTypes.length; j++) {
Class parameterType = parameterTypes[j];
if (j != 0)
System.out.print(" , ");
System.out.print(parameterType.getSimpleName());
}
System.out.println(")");
}
}