java反射詳解實戰代碼

JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意方法和屬性;

        Java反射機制主要提供了以下功能: 在運行時判斷任意一個對象所屬的類;在運行時構造任意一個類的對象;在運行時判斷任意一個類所具有的成員變量和方法;在運行時調用任意一個對象的方法;生成動態代理。

Class反射機制

  1. 指的是可以於運行時加載,探知和使用編譯期間完全未知的類.
  2. 程序在運行狀態中,可以動態加載一個只有名稱的類,對於任意一個已經加載的類,能夠知道這個類的所有屬性和方法;對於任意一個對象,都能調用他的任意一個方法和屬性;
  3. 加載完類之後,在堆內存中會產生一個Class類型的對象(一個類只有一個Class對象),這個對象包含了完整的類的結構信息,而且這個Class對象就像一面鏡子,透過這個鏡子看到類的結構,所以被稱之爲:反射。
  4. 每個類被加載進入內存之後,系統就會爲該類生成一個對應的java.lang.Class對象,通過該Class對象就可以訪問到JVM中的這個類.

Class對象的獲取

  1. 對象的getClass()方法;
  2. 類的.class(最安全/性能最好)屬性;
  3. 運用Class.forName(String className)動態加載類,className需要是類的全限定名(最常用).
        下面用代碼展示一下:

[java] view plain copy
  1. package com.lwl.reflect;  
  2.   
  3. import java.lang.reflect.Constructor;  
  4. import java.lang.reflect.Field;  
  5. import java.lang.reflect.Method;  
  6.   
  7. /** 
  8.  * 獲取類的所有屬性和方法及構造器 
  9.  * @create 2017-10-11 上午11:42:52 
  10.  * @version 1.0 
  11.  */  
  12. public class ReflectAllDemo {  
  13.   
  14.     /** 
  15.      * 獲取類的所有屬性和方法及構造器 
  16.      * @param args 
  17.      * @throws ClassNotFoundException  
  18.      * @create 2017-10-11 上午9:07:46 
  19.      */  
  20.     public static void main(String[] args) throws ClassNotFoundException {  
  21.           
  22.         //根據一個類的全名稱獲取類的類對象  
  23.         //如果類的全名稱錯誤或者不存在,則會報類查詢不到異常:ClassNotFoundException  
  24.         Class<?> clazz = Class.forName("java.lang.String");  
  25.           
  26.         //獲取傳遞過來的類的所有方法  
  27.          Method[]    methods = clazz.getDeclaredMethods();  
  28.          for (Method method : methods) {  
  29.             System.out.println(method.toString());  
  30.         }  
  31.            
  32.         System.out.println("------------------------------我是分隔符:以下是類的屬性--------------------------------");   
  33.         //獲取傳遞過來的類的所有屬性   
  34.         Field[] fields = clazz.getDeclaredFields();  
  35.         for (Field field : fields) {  
  36.             System.out.println(field.toString());  
  37.         }   
  38.           
  39.         System.out.println("------------------------------我是分隔符:以下是構造方法--------------------------------");  
  40.           
  41.         //獲取傳遞過來的類的所有構造方法  
  42.         Constructor<?>[] constructor = clazz.getDeclaredConstructors();  
  43.         for (Constructor<?> ctt : constructor) {  
  44.             System.out.println(ctt.toString());  
  45.         }  
  46.           
  47.     }  
  48.   
  49. }  

創建對象

通過反射來生成對象的方式有兩種:

  1. 使用Class對象的newInstance()方法來創建該Class對象對應類的實例(這種方式要求該Class對象的對應類有默認構造器).
  2. 先使用Class對象獲取指定的Constructor對象,再調用Constructor對象的newInstance()方法來創建該Class對象對應類的實例(通過這種方式可以選擇指定的構造器來創建實例).

調用方法

當獲取到某個類對應的Class對象之後,就可以通過該Class對象的getMethod來獲取一個Method數組或Method對象.

每個Method對象對應一個方法,在獲得Method對象之後,就可以通過調用invoke方法來調用該Method對象對應的方法.

[java] view plain copy
  1. package com.lwl.reflect;  
  2.   
  3. import java.lang.reflect.InvocationTargetException;  
  4. import java.lang.reflect.Method;  
  5.   
  6. /** 
  7.  * 通過反射,對類中的方法進行操作 
  8.  * @create 2017-10-11 上午11:45:57 
  9.  * @version 1.0 
  10.  */  
  11. public class ReflectMethodDemo {  
  12.   
  13.     public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {  
  14.           
  15.           
  16.         Class<?> clazz = Class.forName("com.lwl.reflect.Person");  
  17.         //獲取對象  
  18.         Object instance = clazz.newInstance();  
  19. //      instance = clazz.getDeclaredConstructor(null).newInstance(null);  
  20.           
  21.         //如果已經知道方法的名稱,那麼調用起來更加方便  
  22.         Method method = clazz.getDeclaredMethod("setName"new Class[]{String.class});  
  23.         //設置值  
  24.         method.invoke(instance, new String[]{"jack"});  
  25.   
  26.         System.out.println(instance.toString());  
  27.           
  28.         //獲取值  
  29.         Method getMethod = clazz.getDeclaredMethod("getName"new Class[]{});  
  30.         Object getValue = getMethod.invoke(instance, new String[]{});  
  31.         System.out.println(getValue);  
  32.           
  33.         //對對象中的靜態方法進行訪問  
  34.         Method staticMethod = clazz.getDeclaredMethod("printInfo"new Class[]{});  
  35.         //由於是靜態方法,所以這裏面的 instance 可以不傳,只用用 null 表示  
  36.         Object staticValue = staticMethod.invoke(instance, new String[]{});  
  37. //       staticValue = staticMethod.invoke(null, new String[]{});  
  38.         System.out.println(staticValue);  
  39.           
  40.     }  
  41.   
  42. }  

訪問成員變量

通過Class對象的的getField()方法可以獲取該類所包含的全部或指定的成員變量Field,Filed提供瞭如下兩組方法來讀取和

設置成員變量值.

  1. getXxx(Object obj): 獲取obj對象的該成員變量的值, 此處的Xxx對應8中基本類型,如果該成員變量的類型是引用類型, 則取消get後面的Xxx;
  2. setXxx(Object obj, Xxx val): 將obj對象的該成員變量值設置成val值.此處的Xxx對應8種基本類型, 如果該成員類型是引用類型, 則取消set後面的Xxx;

[java] view plain copy
  1. package com.lwl.reflect;  
  2.   
  3. import java.lang.reflect.Field;  
  4. import java.lang.reflect.InvocationTargetException;  
  5. import java.lang.reflect.Method;  
  6.   
  7. /** 
  8.  * 通過反射,對類中的字段進行操作 
  9.  * @create 2017-10-11 上午11:45:20 
  10.  * @version 1.0 
  11.  */  
  12. public class ReflectFieldDemo {  
  13.   
  14.     public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {  
  15.           
  16.         //獲取類對象  
  17.         Class<?> clazz = Class.forName("com.lwl.reflect.Person");  
  18.         //獲取對象  
  19.         Object instance = clazz.newInstance();  
  20. //      instance = clazz.getDeclaredConstructor(null).newInstance(null);  
  21.           
  22.         //根據屬性的名稱 獲取屬性對象  
  23.         Field field = clazz.getDeclaredField("name");  
  24.         //獲取屬性的類型  
  25.         Class<?> type = field.getType();  
  26.         System.out.println(type); //out print class java.lang.String  
  27.           
  28.         //獲取屬性的名稱  
  29.         String name = field.getName();  
  30.         System.out.println(name);  //out print name  
  31.           
  32.         //由於name屬性是private,如果不設置setAccessible是無法直接對其進行設置  
  33.         //setAccessible是暴力破壞,如果是私有方法同理要設置  
  34.         field.setAccessible(true);  
  35.         field.set(instance, "張三");  
  36.           
  37.         System.out.println(instance.toString()); //out print Person [id=null, name=張三, address=null]  
  38.           
  39.     }  
  40.   
  41. }  

通過反射賦值

[java] view plain copy
  1. package com.lwl.reflect;  
  2.   
  3. import java.lang.reflect.Constructor;  
  4. import java.lang.reflect.Field;  
  5. import java.lang.reflect.InvocationTargetException;  
  6. import java.lang.reflect.Method;  
  7.   
  8. /** 
  9.  * 通過反射,對類對象進行賦值操作 
  10.  * @create 2017-10-11 上午11:44:58 
  11.  * @version 1.0 
  12.  */  
  13. public class ReflectSetValueDemo {  
  14.   
  15.     /** 
  16.      * 用一句話說明這個方法做什麼  
  17.      * @param args 
  18.      * @throws ClassNotFoundException  
  19.      * @throws SecurityException  
  20.      * @throws NoSuchFieldException  
  21.      * @throws NoSuchMethodException  
  22.      * @throws InvocationTargetException  
  23.      * @throws IllegalArgumentException  
  24.      * @throws IllegalAccessException  
  25.      * @throws InstantiationException  
  26.      * @create 2017-10-11 上午9:41:51 
  27.      */  
  28.     public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {  
  29.   
  30.         //獲取類的Class的三種方式  
  31.         /* 
  32.          * 1. Class.forName(類名稱全稱:包括包名) 
  33.          * 2. 類.class  即:Person.class 
  34.          * 3. 對象.getClass()  new Person().getClass(); 
  35.          * */  
  36.         Class<?> clazz = Class.forName("com.lwl.reflect.Person");  
  37. //      clazz = new Person().getClass();  
  38. //      clazz = Person.class;  
  39.           
  40.         //獲取一個屬性  
  41.         Field field = clazz.getDeclaredField("address");  
  42.         System.out.println(field.toString());  
  43.           
  44.         System.out.println("--------------------------------------------我是分隔符:以下是對方法進行操作--------------------------------------------------------");  
  45.           
  46.         //獲取一個方法  
  47.         Method method = clazz.getDeclaredMethod("getName"new Class[]{});  
  48.           
  49.         //傳遞的Class<?>的順序要和方法的參數類型順序保持一致,不然就無法匹配拋出異常:java.lang.NoSuchMethodException  
  50.         Method method1 = clazz.getDeclaredMethod("setName", String.class);  
  51.         //獲取方法的名字  
  52. //      String name = method1.getName();  
  53.         Method method2 = clazz.getDeclaredMethod("setInfo", String.class,Integer.class);  
  54.         //method1 與 method2 還可以使用另外一種方式獲取  
  55.         Method method3 = clazz.getDeclaredMethod("setName"new Class[]{String.class});  
  56.         Method method4 = clazz.getDeclaredMethod("setInfo"new Class[]{String.class,Integer.class});  
  57.           
  58.         System.out.println(method.toString());  
  59.         System.out.println(method1.toString());  
  60.         System.out.println(method2.toString());  
  61.         System.out.println(method3.toString());  
  62.         System.out.println(method4.toString());  
  63.           
  64.         System.out.println("--------------------------------------------我是分隔符:以下是對構造器進行操作--------------------------------------------------------");  
  65.         //因爲默認構造器沒有參數,使用可以傳入null 或者 new Class[]{}  
  66.          Constructor<?> cs =  clazz.getDeclaredConstructor(new Class[]{});  
  67.          //帶參數的構造器  
  68.          Constructor<?> cs2 =  clazz.getDeclaredConstructor(new Class[]{Integer.class,String.class,String.class});  
  69.          System.out.println(cs.toString());  
  70.          System.out.println(cs2.toString());  
  71.            
  72.            
  73.         System.out.println("--------------------------------------------我是分隔符:以下是對反射賦值進行操作--------------------------------------------------------");  
  74.         //根據類的默認構造器 創建一個類對象    
  75.         Object object = cs.newInstance(new Object[]{});  
  76. //      object = cs.newInstance(null);  
  77.         //根據類的帶參數構造器,創建一個類對象  
  78.         Object object2 =    cs2.newInstance(new Object[]{1,"李四","南京"});  
  79. //      object2 = cs2.newInstance(null);  
  80.         System.out.println("原始的對象屬性情況:"+object);   
  81.         System.out.println("原始的對象屬性情況:"+object2);   
  82.           
  83.            
  84.         System.out.println("--------------------------------------------我是分隔符:以下是對反射賦值進行操作:設置開始--------------------------------------------------------");  
  85.           
  86.         //對屬性進行設置值,先獲取所有的方法  
  87.         Method[] methods = clazz.getDeclaredMethods();  
  88.         //獲取類的所有屬性  
  89.         Field[] fields = clazz.getDeclaredFields();  
  90.           
  91.         for (Method m : methods) {  
  92.             //獲取方法的名稱  
  93.             String name = m.getName();  
  94.             //如果名稱是以set開頭的,表示設置值  
  95.             if(name.startsWith("set")){  
  96.                 //獲取set之後的字符串,即屬性的名稱  
  97.                 String fieldName = name.substring(3);  
  98.                 //因爲set之後的首個字符串是大寫,所以要截取第一個字符串轉化爲小寫,這裏千萬別把所有的字符串都轉化爲小寫,防止出現UserName 被轉化爲username  
  99.                 fieldName = fieldName.substring(01).toLowerCase() + fieldName.substring(1);  
  100.                 //這裏會對類中的屬性進行賦值  
  101.                 //由於Person裏面一個特殊的setInfo的方法,且info不是類的屬性,則不會進行賦值  
  102.                 setFieldValue(fieldName, fields, m, object);  
  103.             }  
  104.         }  
  105.         System.out.println("賦值後的對象屬性情況:"+object);   
  106.         System.out.println("賦值後的對象屬性情況:"+object2);   
  107.           
  108.     }  
  109.   
  110.     /** 
  111.      * 給類屬性賦值  
  112.      * @param fieldName 
  113.      * @param fields 
  114.      * @param m 
  115.      * @param object 
  116.      * @throws IllegalAccessException 
  117.      * @throws IllegalArgumentException 
  118.      * @throws InvocationTargetException 
  119.      * @create 2017-10-11 上午10:41:53 
  120.      */  
  121.     public static void setFieldValue(String fieldName, Field[] fields, Method m,  Object object) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException{  
  122.           
  123.         for (Field field : fields) {  
  124.             if (field.getName().equals(fieldName)){  
  125.                 //獲取字段的屬性  
  126.                 Class<?> fieldClass = field.getType();  
  127.                 //如果是Integer 即知道這個是Person的ID  
  128.                 if(fieldClass == Integer.class){  
  129.                     //通過反射設置值:也就是通過object對象,調用當前的 m 方法,後面是 m 方法需要的參數  
  130.                     m.invoke(object, new Integer[]{1});  
  131.                 }  
  132.                 //因爲同爲String的有2個set方法,所有要通過屬性名稱判斷到底是調用哪個  
  133.                 else if (fieldClass == String.class && "name".equals(fieldName)){  
  134.                     //通過反射設置值:也就是通過object對象,調用當前的 m 方法,後面是 m 方法需要的參數  
  135.                     m.invoke(object, new String[]{"jack"});  
  136.                 }  
  137.                 else if (fieldClass == String.class && "address".equals(fieldName)){  
  138.                     //通過反射設置值:也就是通過object對象,調用當前的 m 方法,後面是 m 方法需要的參數  
  139.                     m.invoke(object, new String[]{"南京"});  
  140.                 }  
  141.                 //不需要再次循環  
  142.                 return;  
  143.             }  
  144.         }  
  145.           
  146.     }  
  147.       
  148. }  

使用到的輔助類:

[java] view plain copy
  1. package com.lwl.reflect;  
  2.   
  3. public class Person {  
  4.   
  5.       
  6.     private Integer id;  
  7.       
  8.     private String name;  
  9.       
  10.     private String address;  
  11.   
  12.     public Person() {  
  13.     }  
  14.   
  15.     public Person(Integer id, String name, String address) {  
  16.         this.id = id;  
  17.         this.name = name;  
  18.         this.address = address;  
  19.     }  
  20.   
  21.     public Integer getId() {  
  22.         return id;  
  23.     }  
  24.   
  25.     public void setId(Integer id) {  
  26.         this.id = id;  
  27.     }  
  28.   
  29.     public String getName() {  
  30.         return name;  
  31.     }  
  32.   
  33.     public void setName(String name) {  
  34.         this.name = name;  
  35.     }  
  36.   
  37.     public String getAddress() {  
  38.         return address;  
  39.     }  
  40.   
  41.     public void setAddress(String address) {  
  42.         this.address = address;  
  43.     }  
  44.       
  45.     public void setInfo(String name,Integer id){  
  46.         this.id = id;  
  47.         this.name = name;  
  48.                   
  49.     }  
  50.   
  51.       
  52.     public static void printInfo(){  
  53.         System.out.println("我是靜態方法,我被調用了");  
  54.     }  
  55.       
  56.     @Override  
  57.     public String toString() {  
  58.         return "Person [id=" + id + ", name=" + name + ", address=" + address  
  59.                 + "]";  
  60.     }  
  61.       
  62.       
  63.       
  64.       
  65. }  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章