一、Java反射的理解(反射是研究框架的基礎之一)
Java反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱為Java語言的反射機制。
二、逐步分析
參考:https://blog.csdn.net/u012585964/article/details/52011138
1、關於Class
1、Class是一個類,一個描述類的類(也就是描述類本身),封裝了描述方法的Method,描述字段的Filed,描述構造器的Constructor等屬性
2、對象照鏡子后(反射)可以得到的信息:某個類的數據成員名、方法和構造器、某個類到底實現了哪些接口。
3、對於每個類而言,JRE 都為其保留一個不變的 Class 類型的對象。 一個 Class 對象包含了特定某個類的有關信息。
4、Class 對象只能由系統建立對象
5、一個類在 JVM 中只會有一個Class實例
下面創建一個例子:后面的分析均以此案例為基准。
創建一個空接口:(后面會不斷補充)
1 package com.xfwl.reflection; 2 3 public interface IHuman { 4 5 }
創建一個空基類:(后面會不斷補充)
1 package com.xfwl.reflection; 2 3 public class Human { 4 5 }
創建一個子類:(后面會不斷補充)
1 package com.xfwl.reflection; 2 3 public class Person extends Human implements IHuman { 4 /** 5 * 默認default修飾 6 */ 7 String name; 8 /** 9 * private修飾 10 */ 11 private int age; 12 /** 13 * public修飾 14 */ 15 public char sex='M'; 16 /** 17 * 無參構造 18 */ 19 public Person(){ 20 System.out.println("無參構造!!!"); 21 } 22 /** 23 * 有參構造 24 */ 25 public Person(String name,int age,char sex){ 26 System.out.println("有參構造!!!"); 27 this.name=name; 28 this.age=age; 29 this.sex=sex; 30 } 31 public String getName() { 32 return name; 33 } 34 public void setName(String name) { 35 this.name = name; 36 } 37 public int getAge() { 38 return age; 39 } 40 public void setAge(int age) { 41 this.age = age; 42 } 43 public char getSex() { 44 return sex; 45 } 46 public void setSex(char sex) { 47 this.sex = sex; 48 } 49 public String toString() { 50 return "Person{" + 51 "name='" + name + '\'' + 52 ", age=" + age + 53 ", sex='" + sex + '\'' + 54 '}'; 55 } 56 }
2、反射獲取類對象的三種方式(通過一個Junit測試來說明)
1 package com.xfwl.reflection; 2 3 import org.junit.Test; 4 /** 5 * 測試類 6 * @function 7 * @author 小風微涼 8 * @time 2018-6-3 下午12:28:38 9 */ 10 public class TestAction { 11 /** 12 * 反射機制獲取類有三種方法 13 */ 14 @Test 15 public void testGetClass() throws ClassNotFoundException { 16 Class clazz = null; 17 18 //1 直接通過類名.Class的方式得到 19 clazz = Person.class; 20 System.out.println("通過類名: " + clazz); 21 22 //2 通過對象的getClass()方法獲取,這個使用的少(一般是傳的是Object,不知道是什么類型的時候才用) 23 Object obj = new Person(); 24 clazz = obj.getClass(); 25 System.out.println("通過getClass(): " + clazz); 26 27 //3 通過全類名獲取,用的比較多,但可能拋出ClassNotFoundException異常 28 clazz = Class.forName("com.xfwl.reflection.Person"); 29 System.out.println("通過全類名獲取: " + clazz); 30 } 31 }
運行結果:
通過類名: class com.xfwl.reflection.Person 無參構造!!! 通過getClass(): class com.xfwl.reflection.Person 通過全類名獲取: class com.xfwl.reflection.Person
特別注意:(以下2中方式不會調用構造方法,因為沒有實例化操作)
//1 直接通過類名.Class的方式得到 clazz = Person.class; //3 通過全類名獲取,用的比較多,但可能拋出ClassNotFoundException異常 clazz = Class.forName("com.xfwl.reflection.Person");
3、利用newInstance創建對象:調用的類必須有無參的構造器
1 /** 2 * Class類的newInstance()方法,創建類的一個對象。 3 * @throws ClassNotFoundException 4 * @throws IllegalAccessException 5 * @throws InstantiationException 6 */ 7 @Test 8 public void testNewInstance() 9 throws ClassNotFoundException, IllegalAccessException, InstantiationException { 10 11 Class clazz = Class.forName("com.xfwl.reflection.Person"); 12 13 //使用Class類的newInstance()方法創建類的一個對象 14 //實際調用的類的那個 無參數的構造器(這就是為什么寫的類的時候,要寫一個無參數的構造器,就是給反射用的) 15 //一般的,一個類若聲明了帶參數的構造器,也要聲明一個無參數的構造器 16 Object obj = clazz.newInstance(); 17 System.out.println(obj); 18 }
測試結果:

那么,如果刪除Person.java中的無參構造,繼續測試,結果如下:

4、ClassLoader類加載器

類加載器詳解:
http://blog.csdn.net/ochangwen/article/details/51473120
1 /** 2 * ClassLoader類裝載器 3 */ 4 @Test 5 public void testClassLoader1() throws ClassNotFoundException, IOException { 6 //1、獲取一個系統的類加載器 7 ClassLoader classLoader = ClassLoader.getSystemClassLoader(); 8 System.out.println("系統的類加載器-->" + classLoader); 9 10 //2、獲取系統類加載器的父類加載器(擴展類加載器(extensions classLoader)) 11 classLoader = classLoader.getParent(); 12 System.out.println("擴展類加載器-->" + classLoader); 13 14 //3、獲取擴展類加載器的父類加載器 15 //輸出為Null,無法被Java程序直接引用 16 classLoader = classLoader.getParent(); 17 System.out.println("啟動類加載器-->" + classLoader); 18 19 //4、測試當前類由哪個類加載器進行加載 ,結果就是系統的類加載器 20 classLoader = Class.forName("com.xfwl.reflection.Person").getClassLoader(); 21 System.out.println("當前類由哪個類加載器進行加載-->"+classLoader); 22 23 //5、測試JDK提供的Object類由哪個類加載器負責加載的 24 //輸出為Null,無法被Java程序直接引用 25 classLoader = Class.forName("java.lang.Object").getClassLoader(); 26 System.out.println("JDK提供的Object類由哪個類加載器加載-->" + classLoader); 27 }
測試結果:
系統的類加載器-->sun.misc.Launcher$AppClassLoader@18b4aac2 擴展類加載器-->sun.misc.Launcher$ExtClassLoader@614c5515 啟動類加載器-->null 當前類由哪個類加載器進行加載-->sun.misc.Launcher$AppClassLoader@18b4aac2 JDK提供的Object類由哪個類加載器加載-->null
5、反射機制通過加載器獲取流對象:getResourceAsStream方法
1 /** 2 * 反射機制通過加載器獲取流對象:getResourceAsStream方法 3 * @throws ClassNotFoundException 4 * @throws IOException 5 */ 6 @Test 7 public void testGetResourceAsStream() throws ClassNotFoundException, IOException { 8 //調用getResourceAsStream 獲取類路徑下的文件對應的輸入流 9 /** 10 * 特別說明: 11 * getResourceAsStream("path"),path的路徑和new Person()的位置有關 12 */ 13 14 InputStream in = new Person().getClass().getClassLoader() 15 .getResourceAsStream("com/xfwl/reflection/test.properties"); 16 System.out.println("in: " +in); 17 18 Properties properties = new Properties(); 19 properties.load(in); 20 System.out.println("文件內容:"+properties); 21 System.out.println("name: "+properties.getProperty("name")); 22 System.out.println("age: " + properties.getProperty("age")); 23 System.out.println("sex: "+properties.getProperty("sex")); 24 System.out.println("desc: " + properties.getProperty("desc")); 25 }
test.properties文件內容如下:文件編碼格式:ISO-8859-1
name=\u5C0F\u98CE\u5FAE\u51C9\u0087\u0089 age=23 sex=M desc=\u53CD\u5C04\u673A\u5236\u5B66\u4E60
運行結果:(直接解析會出現亂碼問題,這個可以通過new String(亂碼格式處理參數)來處理)
無參構造!!! in: java.io.BufferedInputStream@215be6bb 文件內容:{age=23, name=小風微涼??, sex=M, desc=反射機制學習} name: 小風微涼?? age: 23 sex: M desc: 反射機制學習
6、反射機制獲取類中的方法:Method: 對應類中的方法
現在給Person類添加一個private 方法、一個public 方法、一個defaut 方法、一個protected方法
1 /** 2 * Java權限有四個,分別為public,protected,默認,private,其開放程度依次降低 3 * public可供所有類訪問 4 * protected繼承可見 5 * private只能類本身內部的方法可以訪問 6 */ 7 public void method_public(){ 8 System.out.println("method_public"); 9 } 10 public void method_public_2(String name,int age,char sex){//public 帶參數 11 System.out.println("method_public_2"); 12 String info="Person{" + 13 "name='" + name + '\'' + 14 ", age=" + age + 15 ", sex='" + sex + '\'' + 16 '}'; 17 System.out.println(info); 18 } 19 protected void method_protected(){ 20 System.out.println("method_protected"); 21 } 22 protected void method_protected_2(String info){//protected 帶參數 23 System.out.println("method_protected_2:"+info); 24 } 25 void method_default(){ 26 System.out.println("method_default"); 27 } 28 void method_default_2(String info){//默認修飾符 帶參數 29 System.out.println("method_default_2:"+info); 30 } 31 private void method_private(){ 32 System.out.println("method_private"); 33 } 34 private void method_private_2(String info){//private 帶參數 35 System.out.println("method_private_2:"+info); 36 }
開始測試如何通過反射機制使用這些方法
1 /** 2 * 如何通過反射機制使用這些方法 3 * @throws ClassNotFoundException 4 * @throws NoSuchMethodException 5 * @throws IllegalAccessException 6 * @throws InstantiationException 7 * @throws InvocationTargetException 8 */ 9 @Test 10 public void testMethod() throws ClassNotFoundException, NoSuchMethodException, 11 IllegalAccessException, InstantiationException, InvocationTargetException { 12 Class clazz = Class.forName("com.xfwl.reflection.Person"); 13 14 //1、得到clazz 對應的類中有哪些方法,不能獲取private方法 15 Method[] methods =clazz.getMethods(); 16 System.out.println("通過反射機制可以拿到的方法:clazz.getMethods()"); 17 for (Method method : methods){ 18 System.out.println(method.getName()); 19 } 20 System.out.println("<-------------------------->"); 21 22 //2、獲取所有的方法(且只獲取當着類聲明的方法,包括private方法) 23 Method[] methods2 = clazz.getDeclaredMethods(); 24 System.out.println("通過反射機制可以拿到的方法:clazz.getDeclaredMethods()"); 25 for (Method method : methods2){ 26 System.out.println(method.getName()); 27 } 28 System.out.println("<-------------------------->"); 29 System.out.println("通過反射機制可以拿到指定的方法:clazz.getDeclaredMethod()"); 30 //3、獲取指定的方法 31 Method method1= clazz.getDeclaredMethod("method_private"); 32 System.out.println("private 無參:"+method1); 33 34 Method method2 = clazz.getDeclaredMethod("method_private_2",String.class);//第一個參數是方法名,后面的是方法里的參數 35 System.out.println("private 有參:"+method2); 36 37 Method method3 = clazz.getDeclaredMethod("method_public_2",String.class,int.class,char.class);//第一個參數是方法名,后面的是方法里的參數 38 System.out.println("public 有參:"+method2); 39 40 //4、執行方法! 41 Object obj = clazz.newInstance(); 42 method3.invoke(obj, "小風微涼", 23,'M'); //執行方法:invoke(類對象) 43 }
測試結果:
通過反射機制可以拿到的方法:clazz.getMethods():不能獲取private/protected/default方法 toString getName setName method_public_2 setAge method_public getSex getAge setSex wait wait wait equals hashCode getClass notify notifyAll <--------------------------> 通過反射機制可以拿到的方法:clazz.getDeclaredMethods():獲取所有修飾權限的方法 toString getName setName method_private_2 method_private method_public_2 setAge method_public method_default method_default_2 getSex getAge setSex method_protected method_protected_2 <--------------------------> 通過反射機制可以拿到指定的方法:clazz.getDeclaredMethod() private 無參:private void com.xfwl.reflection.Person.method_private() private 有參:private void com.xfwl.reflection.Person.method_private_2(java.lang.String) public 有參:private void com.xfwl.reflection.Person.method_private_2(java.lang.String) 無參構造!!! method_public_2 Person{name='小風微涼', age=23, sex='M'}
繼續分析一下:
JDK中的獲取方法
獲取方法:默認只能獲取public修飾的方法
1 @CallerSensitive 2 public Method[] getMethods() throws SecurityException { 3 checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); 4 return copyMethods(privateGetPublicMethods()); 5 }
獲取方法:所有修飾權限的方法都可以獲得
@CallerSensitive public Method[] getDeclaredMethods() throws SecurityException { checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); return copyMethods(privateGetDeclaredMethods(false)); }
獲取方法:獲取指定的方法(所有修飾權限)
1 /** 2 * @jls 8.2 Class Members 3 * @jls 8.4 Method Declarations 4 * @since JDK1.1 5 */ 6 @CallerSensitive 7 public Method getDeclaredMethod(String name, Class<?>... parameterTypes) 8 throws NoSuchMethodException, SecurityException { 9 checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); 10 Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes); 11 if (method == null) { 12 throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes)); 13 } 14 return method; 15 }
分析一下上面這個方法:
String name:方法的名稱
Class<?>... parameterTypes:一個或多個方法參數的類型,注意要一一對應,否則會報錯的哦
執行方法:invoke(方法對象,方法實際參數)
1 @CallerSensitive 2 public Object invoke(Object obj, Object... args) 3 throws IllegalAccessException, IllegalArgumentException, 4 InvocationTargetException 5 { 6 if (!override) { 7 if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { 8 Class<?> caller = Reflection.getCallerClass(); 9 checkAccess(caller, clazz, obj, modifiers); 10 } 11 } 12 MethodAccessor ma = methodAccessor; // read volatile 13 if (ma == null) { 14 ma = acquireMethodAccessor(); 15 } 16 return ma.invoke(obj, args); 17 }
7、反射機制獲取類中的方法:Method: 對應基類或接口中的方法
上面分析了,如何通過反射拿到當前本類里面的各個修飾權限的方法,下面來繼續分析一下,如何讀取父類或實現的接口中的方法:
現在,給父類添加一些方法,在接口中定義一些方法:
接口中的方法聲明:
1 package com.xfwl.reflection; 2 3 public interface IHuman { 4 5 void eat(); 6 void eat(String info); 7 }
Person.java實現接口方法
1 public void eat() { 2 System.out.println("實現接口的方法:eat()無參:"); 3 } 4 public void eat(String info) { 5 System.out.println("實現接口的方法:eat()有參:"+info); 6 }
父類中的方法定義:
1 package com.xfwl.reflection; 2 3 public class Human { 4 public void play_public(){ 5 System.out.println("public無參:play_public"); 6 } 7 public void play_public_2(String info){ 8 System.out.println("public有參:play_public2:"+info); 9 } 10 protected void play_protected(){ 11 System.out.println("protected無參:play_protected"); 12 } 13 protected void play_protected_2(String info){ 14 System.out.println("protected有參:play_protected_2:"+info); 15 } 16 void play_default(){ 17 System.out.println("默認修飾符無參:play_default"); 18 } 19 void play_default_2(String info){//默認修飾符 帶參數 20 System.out.println("默認修飾符有參:play_default_2:"+info); 21 } 22 private void play_private(){ 23 System.out.println("private無參:play_private"); 24 } 25 private void play_private_2(String info){ 26 System.out.println("private有參:play_private_2:"+info); 27 } 28 }
開始測試:
1、拿到當前Person類反射對象,能否得到接口中的方法
1 /** 2 * 反射機制獲取類中的方法:Method: 對應基類或接口中的方法 3 * @throws ClassNotFoundException 4 * @throws SecurityException 5 * @throws NoSuchMethodException 6 * @throws InstantiationException 7 * @throws InvocationTargetException 8 * @throws IllegalArgumentException 9 * @throws IllegalAccessException 10 */ 11 @Test 12 public void testInterfaceOrSupperClass() throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException{ 13 Class clazz = Class.forName("com.xfwl.reflection.Person"); 14 //拿到當前Person類反射對象,能否得到接口中的方法 15 for (Method method : clazz.getMethods()){ 16 System.out.println(method.getName()); 17 } 18 //獲取當前類實現的接口中的方法 19 Method method1= clazz.getDeclaredMethod("eat"); 20 Method method2= clazz.getDeclaredMethod("eat",String.class); 21 //執行 22 method1.invoke(clazz.newInstance()); 23 method2.invoke(clazz.newInstance(),"eat有參數"); 24 }
測試結果:(可以拿到實現的接口中的方法並執行)
toString
getName
setName
eat
eat
method_public_2
setAge
getSex
setSex
getAge
method_public
play_public_2
play_public
wait
wait
wait
equals
hashCode
getClass
notify
notifyAll
無參構造!!!
實現接口的方法:eat()無參:
無參構造!!!
實現接口的方法:eat()有參:eat有參數
2、拿到當前Person類反射對象,能否獲取父類中的方法
通過當前反射對象,拿到父類反射對象
1 Class clazz = Class.forName("com.xfwl.reflection.Person"); 2 Class superClazz = clazz.getSuperclass();
1 /** 2 * 反射機制獲取類中的方法:Method: 對應基類或接口中的方法 3 * @throws ClassNotFoundException 4 * @throws SecurityException 5 * @throws NoSuchMethodException 6 * @throws InstantiationException 7 * @throws InvocationTargetException 8 * @throws IllegalArgumentException 9 * @throws IllegalAccessException 10 */ 11 @Test 12 public void testInterfaceOrSupperClass() throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException{ 13 Class clazz = Class.forName("com.xfwl.reflection.Person"); 14 System.out.println("<------------父類中能夠使用的公共權限的方法------------------------>"); 15 //拿到當前Person類反射對象,能否獲取父類中的方法 16 Class superClazz = clazz.getSuperclass(); 17 for (Method method : superClazz.getMethods()){ 18 System.out.println(method.getName()); 19 } 20 System.out.println("<----------------父類中所有的方法:僅僅父類中的方法-------------------->"); 21 //拿到父類中的所有權限修飾符修飾的方法 22 for (Method method : superClazz.getDeclaredMethods()){ 23 System.out.println(method.getName()); 24 } 25 }
運行結果:
<------------父類中能夠使用的公共權限的方法------------------------> play_public play_public_2 wait wait wait equals toString hashCode getClass notify notifyAll <----------------父類中所有的方法:僅僅父類中的方法--------------------> play_private_2 play_public play_public_2 play_private play_protected play_default play_protected_2 play_default_2
那么可以執行父類中的方法嗎?
1 //是否可以通過子類對象拿到父類中的方法 2 Method method3= clazz.getDeclaredMethod("play_public"); 3 Method method4= clazz.getDeclaredMethod("play_public_2",String.class); 4 Method method5= clazz.getDeclaredMethod("play_private"); 5 Method method6= clazz.getDeclaredMethod("play_private_2",String.class);
上面代碼報錯,說明不可以,public修飾的方法也拿不到
1 Method method7= superClazz.getDeclaredMethod("play_public"); 2 Method method8= superClazz.getDeclaredMethod("play_public_2",String.class); 3 Method method9= superClazz.getDeclaredMethod("play_private"); 4 Method method10= superClazz.getDeclaredMethod("play_private_2",String.class);
上面代碼正常執行,說明父類的反射對象可以拿到自己的public或private方法
1 //使用子類的反射對象執行方法 2 method7.invoke(clazz.newInstance()); 3 method8.invoke(clazz.newInstance(), "play_public_2有參數"); 4 method9.invoke(clazz.newInstance()); //無法執行,Junit報錯 5 method10.invoke(clazz.newInstance(), "play_private_2有參數");//無法執行,Junit報錯
1 //使用父類的反射對象執行方法 2 method7.invoke(superClazz.newInstance()); 3 method8.invoke(superClazz.newInstance(), "play_public_2有參數"); 4 method9.invoke(superClazz.newInstance()); //無法執行,Junit報錯 5 method10.invoke(superClazz.newInstance(), "play_private_2有參數");//無法執行,Junit報錯
上面代碼執行部分報錯,說明通過子類的反射對象和拿到的父類反射對象,也僅僅只能執行public和protected和default默認修飾的方法,不能執行private修飾的方法
7、反射機制獲取類中的字段屬性:Field字段
1 /** 2 * 默認default修飾 3 */ 4 String name; 5 /** 6 * private修飾 7 */ 8 private int age; 9 /** 10 * public修飾 11 */ 12 public char sex='M'; 13 /** 14 * protected修飾 15 */ 16 protected boolean isBeauty=true;
開始測試:如何獲取
1 /** 2 * 反射機制獲取類中的字段屬性:Field字段 3 * @throws ClassNotFoundException 4 * @throws SecurityException 5 * @throws NoSuchFieldException 6 * @throws IllegalAccessException 7 * @throws IllegalArgumentException 8 */ 9 @Test 10 public void testFiled() throws ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException{ 11 //拿到反射Class對象 12 Class clazz = Class.forName("com.xfwl.reflection.Person"); 13 //獲取Field的數組,私有字段也能獲取 14 Field[] fields = clazz.getDeclaredFields(); 15 System.out.println("<----遍歷拿到字段:開始--------------------->"); 16 for (Field field: fields) { 17 System.out.println(field.getName()); 18 } 19 System.out.println("<------------獲取指定名字的Field以及類型--------------------------->"); 20 //獲取指定名字的Field(如果是私有的,見下面的4) 21 Field field1 = clazz.getDeclaredField("name"); 22 System.out.println("獲取指定Field名=: " + field1.getName()+",類型:"+field1.getType()); 23 Field field2 = clazz.getDeclaredField("age"); 24 System.out.println("獲取指定Field名=: " + field2.getName()+",類型:"+field2.getType()); 25 Field field3 = clazz.getDeclaredField("sex"); 26 System.out.println("獲取指定Field名=: " + field3.getName()+",類型:"+field3.getType()); 27 Field field4 = clazz.getDeclaredField("isBeauty"); 28 System.out.println("獲取指定Field名=: " + field4.getName()+",類型:"+field4.getType()); 29 30 System.out.println("<----------獲取指定對象的Field的值 ----------------------------->"); 31 Person person = new Person("小風微涼", 12,'M'); 32 //獲取指定對象的Field的值 33 Object val = field1.get(person); 34 System.out.println("獲取指定對象字段'name'的Field的值=: " + val); 35 36 System.out.println("<----------設置指定對象的Field的值----------------------------->"); 37 //設置指定對象的Field的值 38 field1.set(person, "反射學習A"); 39 System.out.println("設置指定對象字段'name'的Field的值=: " + person.name); 40 41 System.out.println("<----------若該字段是私有的,需要調用setAccessible(true)方法----------------------------->"); 42 //若該字段是私有的,需要調用setAccessible(true)方法 43 field2 = clazz.getDeclaredField("age"); 44 field2.setAccessible(true); 45 System.out.println("獲取指定私有字段名=: " + field2.getName()); 46 }
測試結果:
<----遍歷拿到字段:開始---------------------> name age sex isBeauty <------------獲取指定名字的Field以及類型---------------------------> 獲取指定Field名=: name,類型:class java.lang.String 獲取指定Field名=: age,類型:int 獲取指定Field名=: sex,類型:char 獲取指定Field名=: isBeauty,類型:boolean <----------獲取指定對象的Field的值 -----------------------------> 有參構造!!! 獲取指定對象字段'name'的Field的值=: 小風微涼 <----------設置指定對象的Field的值-----------------------------> 設置指定對象字段'name'的Field的值=: 反射學習A <----------若該字段是私有的,需要調用setAccessible(true)方法-----------------------------> 獲取指定私有字段名=: age
8、反射機制獲取類中的構造器:構造器(Constructor)
Person的構造器
1 /** 2 * 無參構造 3 */ 4 public Person(){ 5 System.out.println("無參構造!!!"); 6 } 7 /** 8 * 有參構造 9 */ 10 public Person(String name,int age,char sex){ 11 System.out.println("有參構造!!!"); 12 this.name=name; 13 this.age=age; 14 this.sex=sex; 15 }
@Test測試
1 /** 2 * 構造器:開發用的比較少 3 */ 4 @Test 5 public void testConstructor() throws ClassNotFoundException, NoSuchMethodException, 6 IllegalAccessException, InvocationTargetException, InstantiationException { 7 String className = "com.xfwl.reflection.Person"; 8 Class<Person> clazz = (Class<Person>) Class.forName(className); 9 10 //1.獲取Constructor對象 11 Constructor<Person>[] constructors = 12 (Constructor<Person>[]) Class.forName(className).getConstructors(); 13 14 System.out.println("<-------------打印所有的構造器---------------------->"); 15 for (Constructor<Person> constructor: constructors) { 16 System.out.println(constructor); 17 } 18 System.out.println("<------------------------------------------------>"); 19 Constructor<Person> constructor = clazz.getConstructor(String.class, int.class,char.class); 20 System.out.println("拿到指定的-->" + constructor); 21 22 //2.調用構造器的newInstance()方法創建對象 23 Object obj= constructor.newInstance("changwen", 11,'M'); 24 }
運行結果:
<-------------打印所有的構造器----------------------> public com.xfwl.reflection.Person() public com.xfwl.reflection.Person(java.lang.String,int,char) <------------------------------------------------> 拿到指定的-->public com.xfwl.reflection.Person(java.lang.String,int,char) 有參構造!!!
9、反射機制獲取類中的注解:注解(Annotation)
基本的 Annotation
自定義 Annotation
1 package com.xfwl.reflection; 2 3 import java.lang.annotation.ElementType; 4 import java.lang.annotation.Retention; 5 import java.lang.annotation.RetentionPolicy; 6 import java.lang.annotation.Target; 7 8 public class Person extends Human implements IHuman { 9 10 @Retention(RetentionPolicy.RUNTIME) //運行時檢驗 11 @Target(value = {ElementType.METHOD}) //作用在方法上 12 public @interface AgeValidator { 13 14 int min(); 15 int max(); 16 } 17 //......其余部分省略 18 }
1 /** 2 * 自定義一個注解:檢查年齡范圍 3 * @function 4 * @author 小風微涼 5 * @time 2018-6-3 下午3:56:03 6 */ 7 @Retention(RetentionPolicy.RUNTIME) //運行時檢驗 8 @Target(value = {ElementType.METHOD}) //作用在方法上 9 public @interface AgeValidator { 10 int min(); 11 int max(); 12 }
@Test測試
1 /** 2 * 通過反射才能獲取注解 3 */ 4 @Test 5 public void testAnnotation() throws Exception { 6 //這樣的方式不能使用注解 7 /*Person person3 = new Person(); 8 person3.setAge(10);*/ 9 10 //拿到反射Class對象 11 String className = "com.xfwl.reflection.Person"; 12 Class clazz = Class.forName(className); 13 Object obj = clazz.newInstance(); 14 //拿到指定方法 15 Method method = clazz.getDeclaredMethod("setAge",int.class); 16 int val =40; 17 18 //獲取注解 19 Annotation annotation = method.getAnnotation(AgeValidator.class); 20 if (annotation != null){ 21 if (annotation instanceof AgeValidator){ 22 AgeValidator ageValidator = (AgeValidator) annotation; 23 24 if (val< ageValidator.min() || val>ageValidator.max()){ 25 throw new RuntimeException("數值超出范圍"); 26 } 27 } 28 } 29 //執行方法 30 method.invoke(obj, val); 31 System.out.println(obj); 32 }
運行結果:
無參構造!!!
Person{name='null', age=40, sex='M'}
獲取指定注解:
//獲取注解 Annotation annotation = method.getAnnotation(AgeValidator.class);
獲取所有注解:
1 //獲取所有注解 2 Annotation[] arr=clazz.getDeclaredAnnotations();
提取 Annotation信息
JDK 的元Annotation
1 package com.xfwl.reflect; 2 3 public class UserBean { 4 5 private String uname; 6 private String upwd; 7 public UserBean(){ 8 this.setUname("xfwl"); 9 this.setUpwd("123456"); 10 } 11 public UserBean(String uname,String upwd){ 12 this.setUname(uname); 13 this.setUpwd(uname); 14 } 15 public void logIn(UserBean user){ 16 System.out.println("用戶登錄:uname="+this.getUname()+",upwd="+this.getUpwd()); 17 } 18 public String getUname() { 19 return uname; 20 } 21 private void logOut(UserBean user){ 22 System.out.println("用戶退出:uname="+this.getUname()+",upwd="+this.getUpwd()); 23 } 24 public void setUname(String uname) { 25 this.uname = uname; 26 } 27 28 public String getUpwd() { 29 return upwd; 30 } 31 32 public void setUpwd(String upwd) { 33 this.upwd = upwd; 34 } 35 }
測試類:ReflectAction.java
1 package com.xfwl.reflect; 2 3 import java.lang.reflect.Method; 4 5 6 public class ReflectAction { 7 /** 8 * @param args 9 */ 10 public static void main(String[] args) { 11 UserBean jack=null; 12 UserBean tom=null; 13 Class tomC=null; 14 try{ 15 jack=(UserBean)Class.forName("com.xfwl.reflect.UserBean").newInstance(); 16 //jack.logIn(); 17 18 tomC=Class.forName("com.xfwl.reflect.UserBean"); 19 tom=(UserBean) tomC.newInstance(); 20 Method[] methods = tomC.getDeclaredMethods(); 21 for (Method method : methods){ 22 if("logOut".equals(method.getName())){ 23 method=tomC.getDeclaredMethod(method.getName(),UserBean.class); 24 System.out.println(method); 25 method.invoke(tomC.newInstance(),tom); 26 } 27 } 28 }catch(Exception e){ 29 30 31 } 32 33 } 34 35 }
運行結果:沒有執行:logOut()
修改:
1 public void logOut(UserBean user){ 2 System.out.println("用戶退出:uname="+this.getUname()+",upwd="+this.getUpwd()); 3 }
即可執行:logOut()
