JAVA反射機制作用是什么

yihu0817 11年前發布 | 61K 次閱讀 反射機制 Java開發 Java

一、什么是反射:
反射的概念是由Smith1982年首次提出的,主要是指程序可以訪問、檢測和修改它本身狀態或行為的一種能力。這一概念的提出很快引發了計算機科學領域關于應用反射性的研究。它首先被程序語言的設計領域所采用,并在Lisp和面向對象方面取得了成績。其中LEAD/LEAD++ OpenC++ MetaXaOpenJava等就是基于反射機制的語言。最近,反射機制也被應用到了視窗系統、操作系統和文件系統中。

反射本身并不是一個新概念,盡管計算機科學賦予了反射概念新的含義。在計算機科學領域,反射是指一類應用,它們能夠自描述和自控制。也就是說,這類應用通過采用某種機制來實現對自己行為的描述(self-representation)和監測(examination),并能根據自身行為的狀態和結果,調 整或修改應用所描述行為的狀態和相關的語義。

二、什么是Java中的類反射:
Reflection
Java 程序開發語言的特征之一,它允許運行中的 Java 程序對自身進行檢查,或者說自審,并能直接操作程序的內部屬性和方法。Java 的這一能力在實際應用中用得不是很多,但是在其它的程序設計語言中根本就不存在這一特性。例如,PascalC 或者 C++ 中就沒有辦法在程序中獲得函數定義相關的信息。
Reflection
Java 被視為動態(或準動態)語言的關鍵,允許程序于執行期 Reflection APIs 取得任何已知名稱之 class 的內部信息,包括 packagetype parameterssuperclassimplemented interfacesinner classes, outer class, fieldsconstructorsmethodsmodifiers,並可于執行期生成instances、變更 fields 內容或喚起 methods

三、Java類反射中所必須的類:
Java
的類反射所需要的類并不多,它們分別是:FieldConstructorMethodClassObject,下面我將對這些類做一個簡單的說明。
Field
類:提供有關類或接口的屬性的信息,以及對它的動態訪問權限。反射的字段可能是一個類(靜態)屬性或實例屬性,簡單的理解可以把它看成一個封裝反射類的屬性的類。
Constructor
類:提供關于類的單個構造方法的信息以及對它的訪問權限。這個類和Field類不同,Field類封裝了反射類的屬性,而Constructor類則封裝了反射類的構造方法。
Method
類:提供關于類或接口上單獨某個方法的信息。所反映的方法可能是類方法或實例方法(包括抽象方法)。 這個類不難理解,它是用來封裝反射類方法的一個類。
Class
類:類的實例表示正在運行的 Java 應用程序中的類和接口。枚舉是一種類,注釋是一種接口。每個數組屬于被映射為 Class 對象的一個類,所有具有相同元素類型和維數的數組都共享該 Class 對象。
Object
類:每個類都使用 Object 作為超類。所有對象(包括數組)都實現這個類的方法。

四、Java的反射類能做什么:
看完上面的這么多我想你已經不耐煩了,你以為我在浪費你的時間,那么好吧!下面我們就用一些簡單的小例子來說明它。
首先我們來看一下通過Java的反射機制我們能得到些什么。
首先我們來寫一個類:

java 代碼

 

  1. import  java.awt.event.ActionListener;  
  2. import  java.awt.event.ActionEvent;  
  3. class  A  extends  Object  implements  ActionListener{  
  4. private   int  a =  3 ;  
  5. public  Integer b =  new  Integer( 4 );  
  6. public  A(){}  
  7. public  A( int  id,String name){}  
  8. public   int  abc( int  id,String name){ return   0 ;}  
  9. public   void  actionPerformed(ActionEvent e){}  
  10. }  


你可能被我這個類弄糊涂了,你看不出我要做什么,那就不要看這個類了,這個類是用來測試的,你知道知道它繼承了Object類,有一個接口是ActionListener,兩個屬性intInteger,兩個構造方法和兩個方法,這就足夠了。
下面我們把A這個類作為一個反射類,來過去A類中的一些信息,首先我們先來過去一下反射類中的屬性和屬性值。

java 代碼

 

  1. import  java.lang.reflect.*;  
  2. class  B{  
  3. public   static   void  main(String args[]){  
  4. A r = new  A();  
  5. Class temp = r.getClass();  
  6. try {  
  7. System.out.println("反射類中所有公有的屬性" );  
  8. Field[] fb =temp.getFields();  
  9. for ( int  j= 0 ;j<fb.length;j++){  
  10. Class cl = fb[j].getType();  
  11. System.out.println("fb:" +cl);  
  12. }  
  13.   
  14. System.out.println("反射類中所有的屬性" );  
  15. Field[] fa = temp.getDeclaredFields();  
  16. for ( int  j= 0 ;j<fa.length;j++){  
  17. Class cl = fa[j].getType();  
  18. System.out.println("fa:" +cl);  
  19. }  
  20. System.out.println("反射類中私有屬性的值" );  
  21. Field f = temp.getDeclaredField("a" );  
  22. f.setAccessible(true );  
  23. Integer i = (Integer)f.get(r);  
  24. System.out.println(i);  
  25. }catch (Exception e){  
  26. e.printStackTrace();  
  27. }  
  28. }  
  29.   
  30. }   


這里用到了兩個方法,getFields()getDeclaredFields(),它們分別是用來獲取反射類中所有公有屬性和反射類中所有的屬性的 方法。另外還有getField(String)getDeclaredField(String)方法都是用來過去反射類中指定的屬性的方法,要注意的是getField方法只能取到反射類中公有的屬性,而getDeclaredField方法都能取到。
這里還用到了Field 類的setAccessible方法,它是用來設置是否有權限訪問反射類中的私有屬性的,只有設置為true時才可以訪問,默認為false。另外 Field類還有set(Object AttributeName,Object value)方法,可以改變指定屬性的值。

下面我們來看一下如何獲取反射類中的構造方法

java 代碼

 

  1. import  java.lang.reflect.*;  
  2. public   class  SampleConstructor {  
  3. public   static   void  main(String[] args) {  
  4. A r = new  A();  
  5. printConstructors(r);  
  6. }  
  7.   
  8. public   static   void  printConstructors(A r) {  
  9. Class c = r.getClass();  
  10. //獲取指定類的類名   
  11. String className = c.getName();  
  12. try  {  
  13. //獲取指定類的構造方法   
  14. Constructor[] theConstructors = c.getConstructors();  
  15. for ( int  i= 0 ; i<theConstructors.length; i++) {  
  16. //獲取指定構造方法的參數的集合   
  17. Class[] parameterTypes = theConstructors[i].getParameterTypes();  
  18.   
  19. System.out.print(className + "(" );  
  20.   
  21. for ( int  j= 0 ; j<parameterTypes.length; j++)  
  22. System.out.print(parameterTypes[j].getName() + " " );  
  23.   
  24. System.out.println(")" );  
  25.   
  26. }  
  27. }catch (Exception e) {  
  28. e.printStackTrace();  
  29. }  
  30. }  
  31. }  

這個例子很簡單,只是用getConstructors()方法獲取了反射類的構造方法的集合,并用Constructor類的getParameterTypes()獲取該構造方法的參數。

下面我們再來獲取一下反射類的父類(超類)和接口

java 代碼

 

  1. import  java.io.*;  
  2. import  java.lang.reflect.*;  
  3.   
  4. public   class  SampleInterface {  
  5. public   static   void  main(String[] args)  throws  Exception {  
  6. A raf = new  A();  
  7. printInterfaceNames(raf);  
  8. }  
  9.   
  10. public   static   void  printInterfaceNames(Object o) {  
  11. Class c = o.getClass();  
  12. //獲取反射類的接口   
  13. Class[] theInterfaces = c.getInterfaces();  
  14. for ( int  i= 0 ; i<theInterfaces.length; i++)  
  15. System.out.println(theInterfaces[i].getName());  
  16. //獲取反射類的父類(超類)   
  17. Class theSuperclass = c.getSuperclass();  
  18. System.out.println(theSuperclass.getName());  
  19. }  
  20. }  


這個例子也很簡單,只是用Class類的getInterfaces()方法獲取反射類的所有接口,由于接口可以有多個,所以它返回一個 Class數組。用getSuperclass()方法來獲取反射類的父類(超類),由于一個類只能繼承自一個類,所以它返回一個Class對象。

下面我們來獲取一下反射類的方法

java 代碼

 

  1. import  java.lang.reflect.*;  
  2. public   class  SampleMethod {  
  3.   
  4. public   static   void  main(String[] args) {  
  5. A p = new  A();  
  6. printMethods(p);  
  7. }  
  8.   
  9. public   static   void  printMethods(Object o) {  
  10. Class c = o.getClass();  
  11. String className = c.getName();  
  12. Method[] m = c.getMethods();  
  13. for ( int  i= 0 ; i<m.length; i++) {  
  14. //輸出方法的返回類型   
  15. System.out.print(m[i].getReturnType().getName());  
  16. //輸出方法名   
  17. System.out.print(" " +m[i].getName()+ "(" );  
  18. //獲取方法的參數   
  19. Class[] parameterTypes = m[i].getParameterTypes();  
  20. for ( int  j= 0 ; j<parameterTypes.length; j++){  
  21. System.out.print(parameterTypes[j].getName());  
  22. if (parameterTypes.length>j+ 1 ){  
  23. System.out.print("," );  
  24. }  
  25. }  
  26.   
  27. System.out.println(")" );  
  28. }  
  29.   
  30. }  
  31.   
  32. }  


這個例子并不難,它只是獲得了反射類的所有方法,包括繼承自它父類的方法。然后獲取方法的返回類型、方法名和方法參數。

接下來讓我們回過頭來想一想,我們獲取了反射類的屬性、構造方法、父類、接口和方法,可這些東西能幫我們做些什么呢!!
下面我寫一個比較完整的小例子,來說明Java的反射類能做些什么吧!!

java 代碼

 

  1. import  java.lang.reflect.Constructor;  
  2. import  java.lang.reflect.Method;  
  3.   
  4. public   class  LoadMethod {  
  5. public  Object Load(String cName,String MethodName,String[] type,String[] param){  
  6. Object retobj = null ;  
  7. try  {  
  8. //加載指定的Java   
  9. Class cls = Class.forName(cName);  
  10.   
  11. //獲取指定對象的實例   
  12. Constructor ct = cls.getConstructor(null );  
  13. Object obj = ct.newInstance(null );  
  14.   
  15. //構建方法參數的數據類型   
  16. Class partypes[] = this .getMethodClass(type);  
  17.   
  18. //在指定類中獲取指定的方法   
  19. Method meth = cls.getMethod(MethodName, partypes);  
  20.   
  21. //構建方法的參數值   
  22. Object arglist[] = this .getMethodObject(type,param);  
  23.   
  24. //調用指定的方法并獲取返回值為Object類型   
  25. retobj= meth.invoke(obj, arglist);  
  26.   
  27. }  
  28. catch  (Throwable e) {  
  29. System.err.println(e);  
  30. }  
  31. return  retobj;  
  32. }  
  33.   
  34. //獲取參數類型Class[]的方法   
  35. public  Class[] getMethodClass(String[] type){  
  36. Class[] cs = new  Class[type.length];  
  37. for  ( int  i =  0 ; i < cs.length; i++) {  
  38. if (!type[i].trim().equals( "" )||type[i]!= null ){  
  39. if (type[i].equals( "int" )||type[i].equals( "Integer" )){  
  40. cs[i]=Integer.TYPE;  
  41. }else   if (type[i].equals( "float" )||type[i].equals( "Float" )){  
  42. cs[i]=Float.TYPE;  
  43. }else   if (type[i].equals( "double" )||type[i].equals( "Double" )){  
  44. cs[i]=Double.TYPE;  
  45. }else   if (type[i].equals( "boolean" )||type[i].equals( "Boolean" )){  
  46. cs[i]=Boolean.TYPE;  
  47. }else {  
  48. cs[i]=String.class ;  
  49. }  
  50. }  
  51. }  
  52. return  cs;  
  53. }  
  54.   
  55. //獲取參數Object[]的方法   
  56. public  Object[] getMethodObject(String[] type,String[] param){  
  57. Object[] obj = new  Object[param.length];  
  58. for  ( int  i =  0 ; i < obj.length; i++) {  
  59. if (!param[i].trim().equals( "" )||param[i]!= null ){  
  60. if (type[i].equals( "int" )||type[i].equals( "Integer" )){  
  61. obj[i]= new  Integer(param[i]);  
  62. }else   if (type[i].equals( "float" )||type[i].equals( "Float" )){  
  63. obj[i]= new  Float(param[i]);  
  64. }else   if (type[i].equals( "double" )||type[i].equals( "Double" )){  
  65. obj[i]= new  Double(param[i]);  
  66. }else   if (type[i].equals( "boolean" )||type[i].equals( "Boolean" )){  
  67. obj[i]=new  Boolean(param[i]);  
  68. }else {  
  69. obj[i] = param[i];  
  70. }  
  71. }  
  72. }  
  73. return  obj;  
  74. }  
  75. }  


這是我在工作中寫的一個實現Java在運行時加載指定的類,并調用指定方法的一個小例子。這里沒有main方法,你可以自己寫一個。
Load
方法接收的五個參數分別是,Java的類名,方法名,參數的類型和參數的值。

結束語:
Java
語言反射提供一種動態鏈接程序組件的多功能方法。它允許程序創建和控制任何類的對象,無需提前硬編碼目標類。這些特性使得反射特別適用于創建以非常普通的方式與對象協作的庫。Java reflection 非常有用,它使類和數據結構能按名稱動態檢索相關信息,并允許在運行著的程序中操作這些信息。Java 的這一特性非常強大,并且是其它一些常用語言,如 CC++Fortran 或者 Pascal 等都不具備的。

但反射有兩個缺點。第一個是性能問題。用于字段和方法接入時反射要遠慢于直接代碼。性能問題的程度取決于程序中是如何使用反射的。如果它作為程序運行中相對很少涉及的部分,緩慢的性能將不會是一個問題。即使測試中最壞情況下的計時圖顯示的反射操作只耗用幾微秒。僅反射在性能關鍵的應用的核心邏輯中使用時性 能問題才變得至關重要。

 

 

package org.hibernate.property;  
 
import java.lang.reflect.Field;  
import java.lang.reflect.Method;  
import java.util.Map;  
 
import org.hibernate.HibernateException;  
import org.hibernate.PropertyAccessException;  
import org.hibernate.PropertyNotFoundException;  
import org.hibernate.engine.SessionFactoryImplementor;  
import org.hibernate.engine.SessionImplementor;  
import org.hibernate.util.ReflectHelper;  
 
/** 
 * Accesses fields directly. 
 * @author Gavin King 
 */ 
public class DirectPropertyAccessor implements PropertyAccessor {  
 
    public static final class DirectGetter implements Getter {  
        private final transient Field field;  
        private final Class clazz;  
        private final String name;  
        DirectGetter(Field field, Class clazz, String name) {  
            this.field = field;  
            this.clazz = clazz;  
            this.name = name;  
        }  
        public Object get(Object target) throws HibernateException {  
            try {  
                return field.get(target);//
返回指定對象上此 Field 表示的字段的值。  
            }  
            catch (Exception e) {  
                throw new PropertyAccessException(e, "could not get a field value by reflection", false, clazz, name);  
            }  
        }  
 
        public Object getForInsert(Object target, Map mergeMap, SessionImplementor session) {  
            return get( target );  
        }  
 
        public Method getMethod() {  
            return null;  
        }  
        public String getMethodName() {  
            return null;  
        }  
        public Class getReturnType() {  
            return field.getType();  
        }  
 
        Object readResolve() {  
            return new DirectGetter( getField(clazz, name), clazz, name );  
        }  
          
        public String toString() {  
            return "DirectGetter(" + clazz.getName() + '.' + name + ')';  
        }  
    }  
 
    public static final class DirectSetter implements Setter {  
        private final transient Field field;  
        private final Class clazz;  
        private final String name;  
        DirectSetter(Field field, Class clazz, String name) {  
            this.field = field;  
            this.clazz = clazz;  
            this.name = name;  
        }  
        public Method getMethod() {  
            return null;  
        }  
        public String getMethodName() {  
            return null;  
        }  
        public void set(Object target, Object value, SessionFactoryImplementor factory) throws HibernateException {  
            try {  
                field.set(target, value);//
將指定對象變量上此 Field 對象表示的字段設置為指定的新值。  
            }  
            catch (Exception e) {  
                if(value == null && field.getType().isPrimitive()) {  
                    throw new PropertyAccessException(  
                            e,   
                            "Null value was assigned to a property of primitive type",   
                            true,   
                            clazz,   
                            name  
                        );                    
                } else {  
                    throw new PropertyAccessException(e, "could not set a field value by reflection", true, clazz, name);  
                }  
            }  
        }  
 
        public String toString() {  
            return "DirectSetter(" + clazz.getName() + '.' + name + ')';  
        }  
          
        Object readResolve() {  
            return new DirectSetter( getField(clazz, name), clazz, name );  
        }  
    }  
 
    private static Field getField(Class clazz, String name) throws PropertyNotFoundException {  
        if ( clazz==null || clazz==Object.class ) {  
            throw new PropertyNotFoundException("field not found: " + name);   
        }  
        Field field;  
        try {  
            field = clazz.getDeclaredField(name);//
返回一個 Field 對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明字段。  
        }  
        catch (NoSuchFieldException nsfe) {  
            field = getField( clazz, clazz.getSuperclass(), name );  
        }  
        if ( !ReflectHelper.isPublic(clazz, field) ) field.setAccessible(true);  
        return field;  
    }  
 
    private static Field getField(Class root, Class clazz, String name) throws PropertyNotFoundException {  
        if ( clazz==null || clazz==Object.class ) {  
            throw new PropertyNotFoundException("field [" + name + "] not found on " + root.getName());   
        }  
        Field field;  
        try {  
            field = clazz.getDeclaredField(name);  
        }  
        catch (NoSuchFieldException nsfe) {  
            field = getField( root, clazz.getSuperclass(), name );  
        }  
        if ( !ReflectHelper.isPublic(clazz, field) ) field.setAccessible(true);  
        return field;  
    }  
      
    public Getter getGetter(Class theClass, String propertyName)  
        throws PropertyNotFoundException {  
        return new DirectGetter( getField(theClass, propertyName), theClass, propertyName );  
    }  
 
    public Setter getSetter(Class theClass, String propertyName)  
        throws PropertyNotFoundException {  
        return new DirectSetter( getField(theClass, propertyName), theClass, propertyName );  
    }  
 

 

 本文由用戶 yihu0817 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!