反射就是透過位元組碼檔案獲取類的成員變數、構造方法和成員方法的所有資訊。
利用反射,我們可以獲取成員變數的修飾符、名字、型別、取值。我們可以獲取構造方法的名字、形參,並利用透過反射獲取的構造方法建立物件。我們可以獲取成員方法的修飾符、名字、形參、返回值、丟擲的異常、註解,並執行透過反射獲取的方法。
比如idea中的自動提示就是透過反射獲取的,idea透過反射獲取該物件的所有能呼叫的方法,並將它顯示出來,又比如idea中函式的形參提示也是透過反射獲取的。
反射是透過位元組碼檔案物件獲取成員變數、成員方法、構造方法的所有資訊,所以,我們先要獲取位元組碼檔案物件,再去從位元組碼檔案物件中獲取成員變數、構造方法和成員方法,最後再進行解剖獲取所有資訊。
獲取class物件的3種方式:
(1)class.forName("全類名");
(2)類名.class;
(3)物件.getClass();
那我們應該如何選擇呢?
建立一個類的物件,我們需要經歷以下3個階段:
- 原始碼階段:Java->class,在這個階段,虛擬機器是沒有把程式碼載入到記憶體當中的,全都是硬碟中進行操作。在這個階段用第一種方式獲取class位元組碼檔案物件。第一種方式最為常用。
- 載入階段:把位元組碼檔案載入到記憶體中。這個階段使用第二種方式來獲取位元組碼檔案物件。第二種方式通常都是當作引數進行傳遞。
- 執行階段:在該階段使用第三種方式。當我們已經有了這個類的物件時才可以使用第三種方式。
利用反射獲取構造方法:
Constructor<?>[] getConstructors()//返回所有公共構造方法物件的陣列
Constructor<?>[] getDeclaredConstructors()//返回所有構造方法物件的陣列
Constructor<T> getConstructor(Class<?>..parameterTypes)//返回單個公共構造方法物件
Constructor<T> getDeclaredConstructor(Class<?>.. parameterTypes)//返回單個構造方法物件
T newInstance(Object... initargs)//根據指定的構造方法建立物件
setAccessible(boolean flag)//設定為true可以繞過訪問控制許可權,使得 private 屬性或方法也可以被訪問。
//setAccessible(boolean flag)使用示例
public class Example {
private String privateField = "privateValue";
}
public class AnotherClass {
public static void main(String[] args) throws Exception {
Example instance = new Example();
Field field = Example.class.getDeclaredField("privateField");
field.setAccessible(true);
System.out.println("Private Field Value: " + field.get(instance)); // 可以透過反射訪問私有欄位
}
}
Class類中用於獲取成員變數的方法:
Field[] getFields()//返回所有公共成員變數物件的陣列
Field[] getDeclaredFields()//返回所有成員變數物件的陣列
Field getField(String name)//返回單個公共成員變數物件
Field getDeclaredField(Stringname)//返回單個成員變數物件
void set(Object obj, Object value)//給成員變數賦值
Object get(Object obj)//獲取成員變數的值。
setAccessible(boolean flag)//使用 setAccessible(true) 可以繞過訪問控制許可權,使得 private 屬性或方法也可以被訪問。
//set,get示例
public class Example {
private String name;
private int age;
public static void main(String[] args) throws Exception {
Example example = new Example();
Field nameField = Example.class.getDeclaredField("name");
Field ageField = Example.class.getDeclaredField("age");
// 設定欄位值
nameField.set(example, "John Doe");
ageField.set(example, 30);
// 獲取欄位值
System.out.println("Name: " + nameField.get(example));
System.out.println("Age: " + ageField.get(example));
}
}
Class類中用於獲取成員方法的方法:
Method[] getMethods()//返回類中所有公共成員方法物件的陣列,包括繼承的
Method[] getDeclaredMethods()//返回類中所有成員方法物件的陣列,不包括繼承的
Method getMethod(String name, Class<?>... parameterTypes)//返回單個公共成員方法物件
Method getDeclaredMethod(String name, Class<?>... parameterTypes)//返回單個成員方法物件
Object invoke(Object obj,Object... args)//執行方法
//引數一:用obj物件呼叫該方法
//引數二:呼叫方法的傳遞的引數(如果沒有就不寫)
//返回值:方法的返回值(如果沒有就不寫)
setAccessible(boolean flag)//使用 setAccessible(true) 可以繞過訪問控制許可權,使得 private 屬性或方法也可以被訪問。
//invoke使用示例:
public class Example {
public void greet(String name) {
System.out.println("Hello, " + name + "!");
}
public static void main(String[] args) throws Exception {
Example example = new Example();
Method method = Example.class.getMethod("greet", String.class);
// 呼叫 greet 方法
method.invoke(example, "John");
}
}
注意:獲取公共方法時也會獲取父類中的所有公共方法。獲取所有許可權的方法時,就不會獲取父類的方法