JAVA反射例の詳細


一:反射
     反射は実行状態において、いずれのクラスに対しても、このクラスのすべての属性と方法を知ることができる.いずれのオブジェクトに対しても、メソッドとプロパティを呼び出すことができます.
  Javaの反射を使用するには、一般的に次の3つのステップがあります.
    1:操作したいクラスのクラスオブジェクトを取得する
    2:手順1で取得したClassオブジェクトから操作クラスを取得する方法または属性名
    3:操作ステップ2で取得する方法または属性
二:例
    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にもロードされることを示します.  @ターゲット内の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("    .....");
	}
}

   スプリングのプロファイルに
<context:annotation-config />
<context:component-scan base-package="com.tanjie.reflect.application"/>
<!--             ,          -->
<bean id="validateErrorMessageExecutor"
	class="com.tanjie.reflect.application.ValidateEnumMark" />

    上記の構成が完了すると、springコンテナが起動すると、まずプログラム全体に重複定義のエラーコードがあるかどうかを検出します.
4:反射のパフォーマンス
       反射があまりよくないところが性能です.反射によってフィールドを取得したり、javaコードを直接使用するよりも方法が遅いからです.しかし、反射がどこに使われているかを見なければなりません.大きなプロジェクトでは、反射が重要ではなく、性能に影響を与えないところにしか使われていない場合、この性能の損失は重要ではありません.