歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

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;
 }
}
</SPAN>

3.3 定義bean

<SPAN >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代碼要慢很多,但是這也得看反射用在什麼地方,在一個大項目中,如果反射僅僅用在無關緊要的,不影響性能的地方,那麼這點性能的丟失也就無關緊要了。

Copyright © Linux教程網 All Rights Reserved