這是關於反射機制的一篇筆記。 視頻教程地址
-
概念:將類的各個組成部分封裝爲其他對象,就是反射機制
-
好處:
- 可以在程序運行中操作這些對象
- 可以解耦,提高程序的可擴展性。
-
獲取class對象的方式:
-
Class.forName("全類名")
:將字節碼文件加載進內存,返回class對象。- 多用於配置文件,將類名定義在配置文件中,讀取文件,加載類。
-
類名.class 通過類名的屬性class獲取
- 多用於參數的傳遞
-
對象.getClass()
:getClass()
方法在Object類中定義着。- 多用於對象的獲取字節碼的方式
-
同一字節碼文件(*.class)在一次程序運行過程中,只會被加載一次,不論通過哪一種方式獲取的class對象都是同一個。
-
代碼
//1.Class.forName("全類名"); Class cls1 = Class.forName("com.qmh.domain.Person"); System.out.println(cls1); //2.類名.class Class cls2 = Person.class; System.out.println(cls2); //3.對象.getClass() Person p = new Person(); Class cls3 = p.getClass(); System.out.println(cls3);
-
-
Class對象功能:
-
獲取成員變量們
public Field[] getFields()
:獲取所有public修飾的成員變量public Field getField(String name)
::獲取指定名稱的public修飾的成員變量public Field[] getDeclaredFields()
:獲取所有的成員變量,不考慮修飾符public Field getDeclaredField(String name)
:獲取指定名稱的成員變量,不考慮修飾符
-
獲取構造方法們
public Constructor<?>[] getConstructors()
public Constructor<T> getConstructor(類<?>... parameterTypes)
public Constructor<?>[] getDeclaredConstructors()
public Constructor<T> getDeclaredConstructor(類<?>... parameterTypes)
-
獲取成員方法們
public Method[] getMethods()
public Method getMethod(String name,類<?>... parameterTypes)
public Method[] getDeclaredMethods()
public Method getDeclaredMethod(String name,類<?>... parameterTypes)
-
獲取類名
String getName()
//獲取類名 String className = personClass.getName(); System.out.println(className);
-
-
Field:成員變量
-
操作:
- 獲取值
public Object get(Object obj)
- 設置值
public void set(Object obj,Object value)
- 忽略訪問權限修飾符的安全檢查
name.setAccessible(true); //暴力反射
- 獲取值
-
代碼:
//1.獲取Person的Class對象 Class<Person> personClass = Person.class; //2.獲取成員變量們 Field[] fields = personClass.getFields(); for(Field field:fields){ System.out.println(field); } System.out.println("--------------"); //3.獲取指定名稱的成員變量 Field a = personClass.getField("a"); //獲取a的值 Person p = new Person(); Object o = a.get(p); System.out.println(o); //設置a的值 a.set(p,"張三"); System.out.println(p); System.out.println("--------------"); //獲取所有的成員變量,不考慮修飾符 Field[] declaredFields = personClass.getDeclaredFields(); for(Field declaredField : declaredFields){ System.out.println(declaredField); } // 訪問某個私有成員變量, Field name = personClass.getDeclaredField("name"); //忽略訪問權限符的安全檢查 name.setAccessible(true); //暴力反射 Object o1 = name.get(p); System.out.println(o1); name.set(p,"李四"); System.out.println(p);
-
-
Constructor:構造方法
- 創建對象
public T newInstance(Object... initargs)
- 如果使用空參數構造方法創建對象,操作可以簡化:Class對象的
newInstance()
方法 - 代碼:
//1.獲取Person的Class對象 Class<Person> personClass = Person.class; //獲取某個構造方法 Constructor<Person> constructor = personClass.getConstructor(String.class, int.class); System.out.println(constructor); //創建對象 Person person = constructor.newInstance("張三", 18); System.out.println(person); System.out.println("--------------"); //空參構造方法 Person person2 = personClass.newInstance(); System.out.println(person2);
- 創建對象
-
Method 方法對象
- 執行方法
public Object invoke(Object obj,Object... args)
- 獲取方法名稱:
method.getName()
- 代碼:
//1.獲取Person的Class對象 Class<Person> personClass = Person.class; // 獲取空參方法 Method eat = personClass.getMethod("eat"); Person p = new Person(); //執行方法 eat.invoke(p); //獲取帶參方法 參數:方法名和參數類 Method eat1 = personClass.getMethod("eat", String.class); //執行方法,傳入對象和參數 eat1.invoke(p, "飯"); //獲取所有public修飾的方法 Method[] methods = personClass.getMethods(); for(Method method:methods){ System.out.println(method); String name = method.getName(); System.out.println(name); }
- 執行方法
-
案例:
-
需求:寫一個“框架”,不能改變該類的任何代碼,可以幫助我們創建任意類的對象,並執行其中任意類的方法
-
實現:
- 配置文件
- 反射
-
步驟
- 將需要創建的對象的全類名和需要執行的方法定義在配置文件中
- 在程序中加載配置文件
- 使用反射技術來加載類文件進內存
- 創建對象
- 執行方法
-
配置文件內容:
className = com.qmh.domain.Student methodName = sleep
-
測試代碼:
public static void main(String[] args) throws Exception { //不能改變該類的任何代碼,可以創建任意類的對象,可以執行任意方法 /*Person p = new Person(); p.eat();*/ //1.加載配置文件 //1.1 創建Properties對象 Properties pro = new Properties(); //1.2加載配置文件,轉換爲一個集合 pro.load(Resources.getResourceAsStream("pro.properties")); //2.獲取配置文件中定義的數據 String className = pro.getProperty("className"); String methodName = pro.getProperty("methodName"); //3.加載該類進內存 Class cls = Class.forName(className); //4.創建對象 無參構造函數 Object o = cls.newInstance(); //5.獲取方法對象 Method method = cls.getMethod(methodName); //6.執行方法 method.invoke(o); }
-