反射機制
反射是一種機制,利用該機制可以在程序運行過程中,對類進行解剖,並獲得操作類中的方法,屬性,構造成員等。
反射就直接操作class字節碼,獲得方法,屬性,構造成員。
反射是在生成字節碼文件之後,對字節碼文件進行的操作。
1、獲取Class對象的三種方式
//創建測試類試Student
public class Student{
//屬性
//行爲
}
方式1、通過類名.class獲取
//格式:類名.class 屬性
//常用場景:反射獲取方式,確定方法的形參列表類型
public void test01(){
Class<Student> cls = Student.class;
}
方式2、通過Object類的成員方法getClass()方法獲取
public void test02(){
Student stu = new Student();
showInfo(stu);
}
public void showInfo(Object obj){
// 方式二 : 使用對象名調用 getClass() 方法.
// 格式 : 對象名.getClass() 方法.
// 使用場景 : 在方法內部, 確定傳入形參的真實類型
Class<?> cls = obj.getClass();
System.out.println("cls="+cls)
}
方式3、通過Class.forName(“全限定類名”)方法獲取
public void test3() throws ClassNotFoundException {
// 方式三 : 使用 Class 調用靜態方法 forName(全限定類名); `包名+類名`
// 使用場景 : 加載外部的配置文件時使用
Class<?> cls = Class.forName("cn.itcast.test2.Student");
System.out.println("cls = " + cls);
}
在獲取類對象之後,介紹幾個Class類中的常用方法
獲取Class中Constructor的相關方法
1.Constructor getConstructor(Class...parameterType);
//根據參數類型獲取構造方法對象,只能獲得public修飾的構造方法。
//如果不存在對應的構造方法,則會拋出 java.lang.NoSuchMethodException 異常。
2.Constructor getDeclaredConstructor(Class...parameter);
//根據參數類型獲取構造方法對象,包括private修飾的構造方法。
//如果不存在對應的構造方法,則會拋出 java.lang.NoSuchMethodException 異常。
3. Constructor[] getConstructors() ;
//獲取所有的public修飾的構造方法
4. Constructor[] getDeclaredConstructors();
//獲取所有構造方法,包括privat修飾的
Constructor類中的常用方法
1. T newInstance(Object... initargs)
//根據指定參數創建對象。
2. void setAccessible(true)
//暴力反射,設置爲可以直接訪問私有類型的構造方法。
示例
學生類
public class Student {
// 屬性
private String name;
private int age;
private char gender;
// 公開構造方法 :
public Student(String name, int age, char gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
// 私有構造方法 :
private Student(String name, int age) {
this.name = name;
this.age = age;
}
// 公開無參構造方法
public Student() {
}
// 行爲
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", gender=" + gender +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
}
示例方法1
public void testConstructor1() throws Exception {
// 1. 獲取 Student 類表示的 Class 對象
Class<?> cls = Class.forName("cn.itcast.test2.Student");
// 2. 調用 getConstructor 方法
Constructor<?> constructor = cls.getConstructor(String.class, int.class, char.class);
// 3. 調用 Constructor 對象的 newInstance 方法, 創建對象
Object obj = constructor.newInstance("柳巖", 18, '女');
// 4. 查看創建的對象
System.out.println("obj = " + obj);
}
```
#### 示例方法2
```
public void testDeclaredConstructor2() throws Exception {
// 1. 獲取 Student 類表示的 Class 對象
Class<?> cls = Class.forName("cn.itcast.test2.Student");
// 2. 調用 getDeclaredConstructor 方法
Constructor<?> constructor = cls.getDeclaredConstructor(String.class, int.class);
// 3. 暴力反射 (設置可訪問權限)
constructor.setAccessible(true);
// 4. 調用 Constructor 對象的 newInstance 方法, 創建對象
Object obj = constructor.newInstance("柳巖", 18);
// 5. 查看創建的對象
System.out.println("obj = " + obj);
}
Class類中與Method相關方法
1. Method getMethod("方法名", 方法的參數類型... 類型) ;
//根據方法名和參數類型獲得一個方法對象,只能是獲取public修飾的
2. Method getDeclaredMethod("方法名", 方法的參數類型... 類型);
//根據方法名和參數類型獲得一個方法對象,包括private修飾的
3. Method[] getMethods() (瞭解);
//獲取所有的public修飾的成員方法,包括父類中。
4. Method[] getDeclaredMethods() (瞭解);
//獲取當前類中所有的方法,包含私有的,不包括父類中。
method類中的常用方法
1. Object invoke(Object obj, Object... args) ;
//根據參數args調用對象obj的該成員方法
//如果obj=null,則表示該方法是靜態方法
2. void setAccessible(boolean flag) ;
//暴力反射,設置爲可以直接調用私有修飾的成員方法
示例代碼1
@Test
public void testMethod1() throws Exception {
// 1. 獲取 Student 類表示的 Class 對象
Class<?> cls = Class.forName("cn.itcast.test2.Student");
// 2. 調用 getMethod 方法
Method eat = cls.getMethod("eat", String.class);
// 3. 調用 invoke 方法
Object obj = cls.getDeclaredConstructor().newInstance();
eat.invoke(obj, "牛肉");
}
示例代碼2
@Test
public void testDeclaredMethod2() throws Exception {
// 1. 獲取 Student 類表示的 Class 對象
Class<?> cls = Class.forName("cn.itcast.test2.Student");
// 2. 調用 declaredMethod 方法
Method sleep = cls.getDeclaredMethod("fallInLove");
// 3. 暴力反射 (設置可訪問權限)
sleep.setAccessible(true);
// 4. 調用 invoke 執行
Object obj = cls.getDeclaredConstructor().newInstance();
sleep.invoke(obj);
}
Class類中與Field相關方法
1. Field getDeclaredField(String name) ;
// 根據屬性名獲得屬性對象,包括private修飾的
2. Field getField(String name) ;
// 根據屬性名獲得屬性對象,只能獲取public修1飾的
3. Field[] getFields() ;
// 獲取所有的public修飾的屬性對象,返回數組。
4. Field[] getDeclaredFields() ;
// 獲取所有的屬性對象,包括private修飾的,返回數組。
Field類中常用方法
void set(Object obj, Object value) ;
Object get(Object obj) ;
void setAccessible(true);
//暴力反射,設置爲可以直接訪問私有類型的屬性。
Class getType();
//獲取屬性的類型,返回Class對象
示例代碼1
public void testField1() throws Exception {
// 1. 獲取 Student 類表示的 Class 對象
Class<?> cls = Class.forName("cn.itcast.test2.Student");
// 2. 調用 getField 方法
Field description = cls.getField("description");
// 3. 設置屬性
Object obj = cls.getDeclaredConstructor().newInstance();
description.set(obj, "這就是那個神奇的學生.");
// 4. 獲取屬性
Object desc = description.get(obj);
System.out.println("desc = " + desc);
}
輸出結果 :
desc = 這就是那個神奇的學生.
代碼示例2
@Test
public void testDeclaredField2() throws Exception {
// 1. 獲取 Student 類表示的 Class 對象
Class<?> cls = Class.forName("cn.itcast.test2.Student");
// 2. 調用 getDeclaredField 方法
Field name = cls.getDeclaredField("name");
// 3. 暴力反射
name.setAccessible(true);
// 4. 設置屬性
Object obj = cls.getDeclaredConstructor().newInstance();
name.set(obj, "渣渣輝");
// 5. 查看
System.out.println(obj);
}
輸出結果 :
Student{name='渣渣輝', age=0, gender= }