Java技術——Java反射機制分析

1. Java的反射機制

動態語言是指在程序運行時允許改變程序結構或者變量類型,從這個觀點看,JAVA和C++一樣,都不是動態語言。但Java它卻有着一個非常突出的動態相關機制:反射

 

Java反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。

 

Java反射機制主要提供了以下功能

(1)在運行時判斷任意一個對象所屬的類

(2)在運行時構造任意一個類的對象

(這一條在下面沒有展示實例,但在之前寫過的一篇Java中創建對象的5種方式中有所介紹,有興趣的可以參考查看。)

(3)在運行時判斷任意一個類所具有的成員變量和方法

(4)在運行時調用任意一個對象的方法

(5)生成動態代理

 

2. Java反射API

反射API用來生成在當前Java虛擬機中的類、接口或者對象的信息。

Class類:反射的核心類,可以獲取類的屬性,方法等內容信息。

Field類:Java.lang.reflect.表示類的屬性,可以獲取和設置類的中屬性值

Method類:Java.lang.reflect。表示類的方法,它可以用來獲取類中方法的信息或者執行方法

Construcor類:Java.lang.reflect。表示類的構造方法

 

3.反射常見用法

3.1 判斷對象是否屬於反射得到的類(isInstance

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. class S {     
  2. }      
  3. public class IsInstance {     
  4.    public static void main(String args[]) {     
  5.       try {     
  6.            Class cls = Class.forName("S");  //創建了一個S類的Class對象  
  7.            boolean b1 = cls.isInstance(new Integer(37));     
  8.            System.out.println(b1);   //fasle  
  9.            boolean b2 = cls.isInstance(new S());     
  10.            System.out.println(b2);   //true  
  11.       }     
  12.       catch (Throwable e) {     
  13.            System.err.println(e);     
  14.       }     
  15.    }     
  16. }   


3.2 獲取某個反射類的所有屬性字段

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. /**  
  2.  * 獲取反射類的所有屬性字段  
  3.  *   
  4.  * @param ownerClass 反射的類  
  5.  * @return  
  6.  * @throws Exception  
  7.  */    
  8. public Field[] getProperty(Class ownerClass) throws Exception {    
  9.     
  10.     //獲取該類所有屬性字段    
  11.     //Field[] fields = ownerClass.getFields();//只獲取public訪問權限的屬性字段(包括父類的)    
  12.     Field[] fields = ownerClass.getDeclaredFields();//只獲取該類的所有訪問權限的屬性(不含父類)    
  13.         
  14.     //輸出所有屬性字段    
  15.     for(int i=0;i<fields.length;i++){    
  16.         System.out.println("屬性:"+fields[i]);    
  17.     }    
  18.     
  19.     return fields;    
  20. }    

3.3 獲取反射類的某個public屬性值

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. /**  
  2.  * 獲取反射類的某個public屬性值  
  3.  *   
  4.  * @param ownerClass 反射的類  
  5.  * @param fieldName 屬性名  
  6.  * @return  
  7.  * @throws Exception  
  8.  */    
  9. public Object getProperty(Object owner,String fieldName) throws Exception {    
  10.         
  11.     //得到對象所屬類    
  12.     Class ownerClass = owner.getClass();    
  13.     
  14.     //獲取該類的某個屬性    
  15.     Field field = ownerClass.getField(fieldName);    
  16.         
  17.     //獲取某個對象的特定屬性    
  18.     Object property = field.get(owner);    
  19.         
  20.     //輸出該屬性信息    
  21.     System.out.println(fieldName+"的屬性值:"+property.toString());    
  22.     
  23.     return property;    
  24.     
  25. }    


3.4 獲取反射類的該中的所有方法

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. /**  
  2.  * 獲取反射類的該中的所有方法  
  3.  * @param ownerClass 反射的類  
  4.  * @return  
  5.  * @throws Exception  
  6.  */    
  7. public Method[] getMethods(Class ownerClass) throws Exception {    
  8.     
  9.     //獲取該類所有方法    
  10.     //Field[] fields = ownerClass.getMethods();//只獲取public訪問權限的方法(包括父類的)    
  11.     Method[] methods = ownerClass.getDeclaredMethods();//只獲取該類的所有訪問權限的方法(不含父類)    
  12.     
  13.     //輸出所有方法    
  14.     for(int i=0;i<methods.length;i++){    
  15.         System.out.println("方法:" +methods[i]);    
  16.     }    
  17.     
  18.     return methods;    
  19. }    


3.5 執行反射類的該中的某個方法

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. /**  
  2.  * 執行反射類的該中的某個方法  
  3.  * @param ownerClass 反射的類  
  4.  * @param methodName 方法名  
  5.  * @return  
  6.  * @throws Exception  
  7.  */    
  8. public Object invokeMethod(Object owner,String methodName,Object[] args) throws Exception {    
  9.     
  10.     //得到對象所屬類    
  11.     Class ownerClass = owner.getClass();    
  12.     
  13.     //獲取該類的某個方法    
  14.     Method method = ownerClass.getMethod(methodName, null);    
  15.         
  16.     //執行某個對象的方法    
  17.     Object result = method.invoke(owner, args);    
  18.         
  19.     //輸出結果信息    
  20.     System.out.println("結果返回值:"+ result);    
  21.     
  22.     return result;    
  23. }    


實例演示方法:

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. /**  
  2.  * 測試反射常用方法  
  3.  */    
  4. public void refTest(){    
  5.     String className = "com.java.reflecttest.Student";    
  6.     
  7.     try {    
  8.             
  9.         //通過反射機制,使用類裝載器,裝載該類    
  10.         Class<?> stu = Class.forName(className);    
  11.         Object objStu = stu.newInstance();    
  12.                     
  13.             
  14.         //獲取反射類的所有屬性    
  15.         System.out.println("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");    
  16.         System.out.println("調用 getProperty 方法,獲取Student類的所有屬性");    
  17.         getProperty(stu);    
  18.             
  19.             
  20.         //獲取反射類的某個屬性值    
  21.         System.out.println("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");    
  22.         System.out.println("調用 getProperty 方法,獲取Student類的NAME屬性值");    
  23.         getProperty(objStu,"NAME");    
  24.             
  25.             
  26.         //獲取反射類的所有方法    
  27.         System.out.println("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");    
  28.         System.out.println("調用 getMethods 方法,獲取Student類的所有方法");    
  29.         getMethods(stu);    
  30.             
  31.         //執行反射類的getInfo方法    
  32.         System.out.println("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");    
  33.         System.out.println("調用 invokeMethod 方法,執行Student類的getInfo方法");    
  34.         invokeMethod(objStu, "getInfo"null);    
  35.             
  36.             
  37.     } catch (Exception e) {    
  38.         e.printStackTrace();    
  39.     }    
  40. }    

演示所用的Student類:

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. package com.java.reflecttest;    
  2.     
  3. /**  
  4.  * 學生信息類  
  5.  *   
  6.  * @author Longxuan  
  7.  *  
  8.  */    
  9. public class Student {    
  10.     
  11.     /**  
  12.      * 學號  
  13.      */    
  14.     private String stuId ;    
  15.         
  16.     /**  
  17.      * 學號  
  18.      */    
  19.     public String STUID;    
  20.         
  21.     /**  
  22.      * 姓名  
  23.      */    
  24.     private String name ;    
  25.         
  26.     /**  
  27.      * 姓名  
  28.      */    
  29.     public String NAME;    
  30.     
  31.     /**  
  32.      * 年齡  
  33.      */    
  34.     private int age;    
  35.         
  36.     /**  
  37.      * 年齡  
  38.      */    
  39.     public int AGE;    
  40.         
  41.     /**  
  42.      * 班級  
  43.      */    
  44.     private String classid;    
  45.         
  46.     
  47.     
  48.         
  49.     public String getStuId() {    
  50.         return stuId;    
  51.     }    
  52.     
  53.     public void setStuId(String stuId) {    
  54.         this.stuId = stuId;    
  55.     }    
  56.     
  57.     public String getName() {    
  58.         return name;    
  59.     }    
  60.     
  61.     public void setName(String name) {    
  62.         this.name = name;    
  63.     }    
  64.     
  65.     public int getAge() {    
  66.         return age;    
  67.     }    
  68.     
  69.     public void setAge(int age) {    
  70.         this.age = age;    
  71.     }    
  72.     
  73.     public String getClassid() {    
  74.         return classid;    
  75.     }    
  76.     
  77.     public void setClassid(String classid) {    
  78.         this.classid = classid;    
  79.     }    
  80.         
  81.         
  82.     /**  
  83.      * 輸出學生信息  
  84.      */    
  85.     public void getInfo(){    
  86.         System.out.println("學生信息:\n學號:"+stuId+"\t姓名:"+name+"\t年齡:"+age+"\t班級:"+classid);    
  87.     }    
  88.         
  89.     /**  
  90.      * 構造函數  
  91.      */    
  92.     public Student(){    
  93.         init();    
  94.     }    
  95.         
  96.         
  97.     /**  
  98.      * 私有初始化方法  
  99.      */    
  100.     private void init(){    
  101.         this.name = "張三";    
  102.         this.stuId ="1001";    
  103.         this.age = 14;    
  104.         this.classid = "A001";    
  105.         this.NAME = name;    
  106.         this.AGE = age;    
  107.         this.STUID = stuId;    
  108.     }    
  109.         
  110. }    


運行結果:


4. 反射的效率

在Stackoverflow上認爲反射比較慢的程序員主要有如下看法,如果你面試遇到了,可以這樣回答:

(1)驗證等防禦代碼過於繁瑣,這一步本來在link階段,現在卻在計算時進行驗證。

(2)產生很多臨時對象,造成GC與計算時間消耗。

(3)由於缺少上下文,丟失了很多運行時的優化,比如JIT(它可以看作JVM的重要評測標準之一)

 

當然,我個人的看法是,現代JVM也不是非常慢了,它能夠對反射代碼進行緩存以及通過方法計數器同樣實現JIT優化,所以反射不一定慢。更重要的是,很多情況下,你自己的代碼纔是限制程序的瓶頸。因此,在開發效率遠大於運行效率的的基礎上,大膽使用反射,放心開發吧。


文章轉自:http://blog.csdn.NET/xiaoxian8023/article/details/9206055

http://www.jianshu.com/p/f83556bcae59

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章