1. 程式人生 > >JAVA反射例項詳解與介紹

JAVA反射例項詳解與介紹

我們都知道Java反射很重要,這次我來拋個磚頭奮鬥!!!

一:反射

   反射是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性。

  使用java的反射,一般有下面三步:

    1:獲得你想操作類的Class物件

    2:通過第一步獲得的Class物件去取得操作類的方法或是屬性名

    3:操作第二步取得的方法或是屬性

二:例子

    Java的反射機制中類有Class對應,類的方法有Method對應,當然屬性也有Field與之對應。

2.1 通過反射獲取當前類和父類的相關屬性

public class GetOtherClassFiled {  
    public static void main(String[] args) throws ClassNotFoundException {  
        Class<?> demo = Class.forName("com.tanjie.reflect.Persons");  
        System.out.println("獲取當前類的所有屬性:=========================");  
        Field field[] = demo.getDeclaredFields();  
        for(int i=0;i<field.length;i++){  
            int mo = field[i].getModifiers();  
            //修飾符  
            String prev = Modifier.toString(mo);  
            //屬性型別  
            Class<?> type = field[i].getType();  
            System.out.println(prev + " " + type.getName() + " " + field[i].getName());  
        }  
        System.out.println("實現的父類介面屬性:============================");  
        Field field2[] = demo.getFields();  
        for(int j=0;j<field2.length;j++){  
            int mo = field2[j].getModifiers();  
            String prev = Modifier.toString(mo);  
            Class<?> type = field2[j].getType();  
            System.out.println(prev + " " + type.getName() + " " + field2[j].getName());  
        }  
     }  
  
} 
執行結果:
獲取當前類的所有屬性:=========================  
private java.lang.String name  
實現的父類介面屬性:============================  
public static final java.lang.String name
 2.2 獲取類的相關屬性,建構函式,介面
public class ClassImplesWhichInterface {  
      public static void main(String[] args) throws Exception {  
        Class<?> demo = Class.forName("com.tanjie.reflect.Persons");  
         //獲取介面類  
         Class<?> interfaces[] = demo.getInterfaces();  
        //獲取父類  
         Class<?> parents = demo.getSuperclass();  
         //獲取所有的建構函式  
         Constructor<?> constructors[] = demo.getConstructors();  
         for (int i = 0; i < interfaces.length; i++) {  
             System.out.println("實現了哪些介面類:" + interfaces[i].getName());  
         }  
         for (int i = 0; i < constructors.length; i++) {  
             System.out.println("類有哪些建構函式:" + constructors[i]);  
         }  
         System.out.println("繼承的父類:" + parents.getName());  
         for (int i = 0; i < constructors.length; i++) {  
           Class<?> paramenter[] = constructors[i].getParameterTypes();  
           int mo = constructors[i].getModifiers();  
           System.out.println(Modifier.toString(mo) + " " + constructors[i].getName());  
           for(int j=0;j<paramenter.length;j++){  
               System.out.println(paramenter[j].getName());  
          }  
          }  
       }  
}

執行結果:
實現了哪些介面類:com.tanjie.reflect.Parents  
類有哪些建構函式:public com.tanjie.reflect.Persons()  
類有哪些建構函式:public com.tanjie.reflect.Persons(java.lang.String)  
繼承的父類:java.lang.Object  
public com.tanjie.reflect.Persons  
public com.tanjie.reflect.Persons  
java.lang.String

三:實際應用

       上面2個列子我們熟悉了反射常用的方式,記不住的時候,翻翻api就會使用了,反射對應的方法都簡單明瞭,下面我們來看一個具體在專案中利用反射的例子。

  假如我們有這樣一個需求,在你的程式中,常常有一些定義錯誤碼的列舉類,而錯誤編碼怎樣才能保證不會被重複定義呢,如果每次定義的時候都去手動檢查一下肯定是非常麻煩的,我們可以利用反射來實現動態的錯誤碼檢測

 3.1 定義一個註解類

@Retention(RetentionPolicy.RUNTIME)  
@Target(ElementType.TYPE)  
public @interface EnumTag {  
  String name();  
}  

RetentionPolicy.RUNTIME:表示在原始碼,編譯後的.class都儲存資訊,在執行的時候也會把這些資訊載入到JVM中。
  @Target裡面的ElementType是用來制定Annotation可以用在那一種型別。

  3.2 定義列舉類  

@EnumTag(name = "errorEnum")  
public enum ErrorEnum {  
      
    JAVA_TIME_OUT(1000),  
      
    ZOOKEEPER_TIME_OUT(2000);  
  
    private final int errorCode;  
  
    private final String errMessage;  
  
    /** 
     * 列舉類建構函式,初識化 
     *  
     * @param errorCode 
     *            errorCode 
     */  
    private ErrorEnum(int errorCode) {  
        this.errorCode = errorCode;  
        this.errMessage = "System Error";  
    }  
  
    public int getErrorCode() {  
        return errorCode;  
    }  
  
    public String getErrMessage() {  
        return errMessage;  
    }  
  
    public static List<Integer> getErrorCodes() {  
        List<Integer> errorCodeList = new ArrayList<Integer>();  
        for (final ErrorEnum em : ErrorEnum.values()) {  
            int code = em.getErrorCode();  
            errorCodeList.add(code);  
        }  
        return errorCodeList;  
    }  
}  

 3.3 定義bean
public class ValidateEnumMark implements InitializingBean {  
  
    private List<Integer> errorList;  
  
    public ValidateEnumMark() {  
        errorList = new ArrayList<Integer>();  
    }  
  
    /** 
     *  
     * 在初始化之前做的事情通過@PostConstruct和 @PreDestroy方法實現初始化和銷燬bean之前進行的操作 
     *  
     * @throws SecurityException 
     * @throws NoSuchMethodException 
     * @throws InvocationTargetException 
     * @throws IllegalArgumentException 
     * @throws IllegalAccessException 
     * 
     */  
    @SuppressWarnings("unchecked")  
    @PostConstruct  
    public void validate() throws NoSuchMethodException, SecurityException,  
            IllegalAccessException, IllegalArgumentException,  
            InvocationTargetException {  
        Reflections reflections = new Reflections(  
                "com.tanjie.reflect.application");  
        Set<Class<?>> sets = reflections.getTypesAnnotatedWith(EnumTag.class);  
        for (Class<?> demo : sets) {  
            // 通過反射獲取指定方法  
            Method method = demo.getDeclaredMethod("getErrorCodes",  
                    new Class[] {});  
            // 通過反射呼叫其它類的方法  
            List<Integer> list = (List<Integer>) method.invoke(demo,  
                    new Object[] {});  
            if (null != list && !list.isEmpty()) {  
                for (Integer integer : list) {  
                    if (errorList.contains(integer)) {  
                        System.out.println("錯誤編碼重複");  
                    } else {  
                        errorList.add(integer);  
                    }  
                }  
            }  
        }  
                System.out.println("目前服務中定義的錯誤碼有:" + errorList);  
    }  
  
    @Override  
    public void afterPropertiesSet() throws Exception {  
        System.out.println("校驗完成.....");  
    }  
}
在spring的配置檔案裡面

<context:annotation-config />
<context:component-scan base-package="com.tanjie.reflect.application"/>  
<!-- 在載入所有的配置檔案之前,檢測錯誤碼是否重複 -->  
<bean id="validateErrorMessageExecutor"  
    class="com.tanjie.reflect.application.ValidateEnumMark" />

 完成上面的配置後,spring容器在啟動時,首先就會檢測你整個程式中是否存在重複定義的錯誤碼了。

4:反射的效能

       反射不太好的地方就是效能了,因為通過反射來獲取欄位或者方法比直接使用java程式碼要慢很多,但是這也得看反射用在什麼地方,在一個大專案中,如果反射僅僅用在無關緊要的,不影響效能的地方,那麼這點效能的丟失也就無關緊要了。