Java 反射(基礎)
一、反射的概述
JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制。
要想解剖一個類,必須先要獲取到該類的位元組碼檔案物件。而解剖使用的就是Class類中的方法.所以先要獲取到每一個位元組碼檔案對應的Class型別的物件.
例如:一個類有:成員變數、方法、構造方法、包等等資訊,利用反射技術可以對一個類進行解剖,把個個組成部分對映成一個個物件。
1、獲取Class物件
獲取類物件的三種方式,1已經可以建立實體類了,再用反射,多此一舉;2需要配置檔案支援;3通過全限定名獲取,一般常用
2獲取構造器
請注意圖中的修飾符和引數
@Test//獲取構造器 public void objTest3() { System.out.println("**********************************獲取所有構造器**********************************"); Class<?> aClass = null; try { aClass = Class.forName("com.example.reflex.Student"); } catch (ClassNotFoundException e) { e.printStackTrace(); } Constructor<?>[] constructors = aClass.getConstructors(); System.out.println("**********************************獲取所有公共構造器**********************************"); for (Constructor<?> constructor : constructors) { System.out.println("構造器輸出 : " + constructor); } System.out.println("**********************************獲取所有構造器(包括私有,受保護的)**********************************"); Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors(); for (Constructor<?> declaredConstructor : declaredConstructors) { System.out.println("構造器輸出 : " + declaredConstructor); } System.out.println("**********************************獲取預設的構造器(公有無參)**********************************"); Constructor<?> constructor = null; try { constructor = aClass.getConstructor(null); } catch (NoSuchMethodException e) { e.printStackTrace(); } System.out.println("構造器輸出:" + constructor); }
控制檯輸出結果
getConstructors 獲取所有公共的構造器;getDeclaredConstructors 獲取所有構造器,包括私有,受保護的
獲取私有構造器,並呼叫
@Test//獲取私有構造器並呼叫 public void objTest4() { Class<?> aClass = null; try { aClass = Class.forName("com.example.reflex.Student"); } catch (ClassNotFoundException e) { e.printStackTrace(); } Constructor<?> declaredConstructor = null; try { //反射獲取構造方法物件 declaredConstructor = aClass.getDeclaredConstructor(int.class);//String.class char.class int.class } catch (NoSuchMethodException e) { e.printStackTrace(); } System.out.println("構造方法:" + aClass); declaredConstructor.setAccessible(true);//開啟暴力訪問,忽略訪問修飾符 try { //構造方法中新增屬性、返回T型別 Object newInstance = declaredConstructor.newInstance(18); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } }
控制檯輸出結果
getDeclaredConstructor(int.class) 指定獲取構造器,引數int
反射回的物件.setAccessible(true); 開啟暴力模式,忽略修飾符
3獲取成員變數
@Test//獲取成員變數 public void Fields() { Class<?> aClass = null; try { aClass = Class.forName("com.example.reflex.reflexOfEntity"); } catch (ClassNotFoundException e) { e.printStackTrace(); } Field[] fields = aClass.getFields(); System.out.println("**********************************獲取公有成員變數**********************************"); for (Field field : fields) { System.out.println("成員變數:" + field); } System.out.println("**********************************獲取所有成員變數(包括私有、受保護、預設的)**********************************"); Field[] declaredFields = aClass.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println("成員變數:" + declaredField); } }
控制檯輸出結果
注意修飾符和成員變數名稱
類物件.getFields 獲取所有公有的成員變數; 類物件.getDeclaredFields 獲取所有的成員變數,包括私有的,受保護的,預設的;
@Test//獲取私有成員變數並呼叫 public void Fields2() { System.out.println("**********************************獲取私有屬性並呼叫**********************************"); Class<?> aClass = null; try { aClass = Class.forName("com.example.reflex.reflexOfEntity"); } catch (ClassNotFoundException e) { e.printStackTrace(); } Field[] declaredFields = aClass.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println("遍歷所有成員變數:" + declaredField); } //private java.lang.String com.example.reflex.reflexOfEntity.phoneNum 獲取到的私有成員變數 Field phoneNum = null; try { phoneNum = aClass.getDeclaredField("phoneNum"); } catch (NoSuchFieldException e) { e.printStackTrace(); } System.out.println("輸出私有成員變數:" + phoneNum); //反射類物件 Object newInstance = null; try { newInstance = aClass.getConstructor().newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } phoneNum.setAccessible(true);//開啟暴力模式,忽略修飾符 try { phoneNum.set(newInstance,"222"); } catch (IllegalAccessException e) { e.printStackTrace(); } reflexOfEntity reflexOfEntity = (reflexOfEntity) newInstance;//獲取類例項化物件 System.out.println("輸出物件,檢視phoneNum屬性:" + reflexOfEntity); }
控制檯輸出
私有的成員變數 phoneNum 被賦值
類物件.getConstructor().newInstance(); 獲取類例項化物件
成員變數物件.set(類例項化物件,"222");
aClass.getDeclaredField("phoneNum"); aClass(類物件)phoneNum (成員變數名稱)
4獲取方法
@Test//獲取方法 public void testMethod() { //獲取類物件 Class<?> aClass = null; try { aClass = Class.forName("com.example.reflex.reflexOfMethod"); } catch (ClassNotFoundException e) { e.printStackTrace(); } System.out.println("**********************************獲取所有共有方法**********************************"); //獲取所有的共有方法 Method[] methods = aClass.getMethods(); for (Method method : methods) { System.out.println("共有方法:" + method); } System.out.println("**********************************獲取所有(自定義)方法(包括私有,預設,受保護的)**********************************"); //獲取所有方法 Method[] declaredMethods = aClass.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.println("所有方法:" + declaredMethod); } }
控制檯輸出
注意方法名,修飾符,包名
getMethods();獲取所有共有方法,包括Java內設方法 ; getDeclaredMethods()獲取所有自定義方法,包括私有的,受保護的,預設的;
@Test//獲取指定方法,並呼叫 public void testMethod2() { //獲取類物件 Class<?> aClass = null; try { aClass = Class.forName("com.example.reflex.reflexOfMethod"); } catch (ClassNotFoundException e) { e.printStackTrace(); } System.out.println("獲取類物件:" + aClass); System.out.println("**********************************獲取所有(自定義)方法(包括私有,預設,受保護的)**********************************"); //獲取自定義所有方法 Method[] declaredMethods = aClass.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.println("檢視方法:" + declaredMethod); } //public void com.example.reflex.reflexOfMethod.show1(java.lang.String)公有方法show1 //private java.lang.String com.example.reflex.reflexOfMethod.show4(int)私有方法show4 //呼叫指定方法 Method show1 = null; try { show1 = aClass.getMethod("show1", String.class); } catch (NoSuchMethodException e) { e.printStackTrace(); } System.out.println("獲得方法:" + show1); //獲取類例項化物件 Object newInstance = null; try { newInstance = aClass.getConstructor().newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } Object chenyb = null; try { chenyb = show1.invoke(newInstance, "Chenyb"); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } System.out.println("呼叫方法show1,輸出返回值:" + chenyb); Method show4 = null; try { show4 = aClass.getDeclaredMethod("show4", int.class); } catch (NoSuchMethodException e) { e.printStackTrace(); } System.out.println("獲得私有方法:" + show4); //呼叫類物件 show4.setAccessible(true);//暴力呼叫,忽略修飾符 Object invoke = null; try { invoke = show4.invoke(newInstance, 18); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } System.out.println("呼叫方法show4,輸出返回值:" + invoke); }
控制檯輸出
-
以上環節,注意開啟暴力許可權的步奏,和引數型別 型別 型別
2018-09-05
Chenyb 隨筆記錄,方便自己學習(學習到了Java 執行緒&反射,才感覺自己java 才剛剛入門)