Java利用反射實現注解簡單功能


//自定義一個簡單的注解
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD,ElementType.PARAMETER,ElementType.LOCAL_VARIABLE})
public @interface Dougest { String value() default ""; }
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.lang.annotation.Annotation;
//方法測試類
@Dougest("annotation Dougest at class ")
public class TestAnnotation {
    @Dougest("annotation Dougest at field")
    String a = "2";
    @Dougest
    int b = 10000000;
    
    public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
        TestAnnotation testAnnotation = new TestAnnotation();
        testAnnotation.a = "123";
        System.out.println(getObjectFieldsValue(testAnnotation));//結果 ==> {a=123, b=10000000}
        System.out.println(getObjectFieldValueByFieldName(testAnnotation,"a"));//結果 ==> 123
        System.out.println(getFieldValueByAnnotation(Dougest.class, testAnnotation));//結果 ==> {a=123, b=10000000}
        Dougest d = (Dougest)TestAnnotation.class.getAnnotation(Dougest.class);//結果 ==> 
        System.out.println(d.value());//結果 ==> annotation Dougest at class 
    }
    
    /**
     * 獲取指定對象指定注解下屬性值
     * @param annotation
     * @param obj
     * @return
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     */
    public static Object getFieldValueByAnnotation(Class<? extends Annotation> annotation,Object obj) throws IllegalArgumentException, IllegalAccessException{
        if(obj == null)
            throw new RuntimeException("cannot getFieldValueByAnnotation for null Object");
        if(annotation == null)
            throw new RuntimeException("cannot getFieldValueByAnnotation for null annotation");
        Map<String,Object> map = new HashMap<String,Object>();
        Field[] fields = obj.getClass().getDeclaredFields();
        for(Field field : fields) {
            field.setAccessible(true);
            if(field.isAnnotationPresent(annotation)) {
                map.put(field.getName(),field.get(obj));
            }
        }
        return map;
    }
    
    /**
     * 獲取對象屬性值
     * @param obj
     * @return
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     */
    @SuppressWarnings("rawtypes")
    public static Map<String,Object> getObjectFieldsValue(Object obj) throws IllegalArgumentException, IllegalAccessException {
        if(obj == null)
            throw new RuntimeException("cannot getObjectFieldsValue for null Object");
        Map<String,Object> map = new HashMap<String,Object>();
        Class clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for(Field field : fields) {
            field.setAccessible(true);
            map.put(field.getName(), field.get(obj));
        }
        return map;
    }
    /**
     * 獲取對象屬性名獲取屬性值
     * @param obj
     * @return
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     */
    @SuppressWarnings("rawtypes")
    public static Object getObjectFieldValueByFieldName(Object obj,String fieldName) throws IllegalArgumentException, IllegalAccessException {
        if(obj == null)
            throw new RuntimeException("cannot getObjectFieldValueByFieldName for null Object");
        if(fieldName == null || "".equals(fieldName.trim()))
            throw new RuntimeException("cannot getObjectFieldValueByFieldName for null fieldName");
        Class clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for(Field field : fields) {
            field.setAccessible(true);
            if(fieldName.equals(field.getName())) 
                return field.get(obj);
        }
        return null;
    }
}

什么是注解(what)

定義:

  注解(Annotation),也叫元數據。一種代碼級別的說明。它是JDK1.5及以后版本引入的一個特性,與類、接口、枚舉是在同一個層次。它可以聲明在包、類、字段、方法、局部變量、方法參數等的前面,用來對這些元素進行說明,注釋。

我的理解:

   吾生而有涯,其學也無涯,以有涯隨無涯,殆①已!
  注: ①殆 :危險
 
作用(why):

編寫文檔:通過代碼里標識的元數據生成文檔。
代碼分析:通過代碼里標識的元數據對代碼進行分析。
編譯檢查:通過代碼里標識的元數據讓編譯器能實現基本的編譯檢查

我的理解:解釋代碼
  
元注解:
  @Target 中 ElementType ( ElementType     ==> 作用域范圍):
    1. CONSTRUCTOR:        用於描述構造器
    2. FIELD:                         用於描述域
    3. LOCAL_VARIABLE:    用於描述局部變量
    4. METHOD:                    用於描述方法
    5. PACKAGE:                  用於描述包
    6. PARAMETER:             用於描述參數
    7. TYPE:                       用於描述類、接口(包括注解類型) 或enum聲明
  ElementType 的取值可以不止有一個,如下原碼:
 
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
    /**
     * Declares whether the annotated dependency is required.
     * <p>Defaults to {@code true}.
     */
    boolean required() default true;
}
代碼的生命周期對應 @Retention
    1   源碼(人可以識別的字符)階段  xx.java
     2  編譯階段  xx.class
     3  執行階段(被jvm加載交給CPU運行階段)byte[]
    注解
          SOURCE     對應源碼階段
          CLASS        對應編譯階段
           RUNTIME     隨時,包含上面兩個階段
 
 
 
應用場景
1.編譯檢查        @SupperessWarnings
2.在框架中使用,一般都會聲明為runtime
        根據Annotation不同利用反射機制讀取出Annotation中的內容
        從而根據不同的內容實現不同的邏輯
3.根據Annotation生成幫助文檔        @Document
4.能夠幫助我們提高代碼的識別度  @Override
 

自定義注解(詳情見最上面代碼):

  使用@interface自定義注解時,自動繼承了java.lang.annotation.Annotation接口,由編譯程序自動完成其他細節。在定義注解時,不能繼承其他的注解或接口。@interface用來聲明一個注解,其中的每一個方法實際上是聲明了一個配置參數。方法的名稱就是參數的名稱,返回值類型就是參數的類型(返回值類型只能是基本類型、Class、String、enum)。可以通過default來聲明參數的默認值。

  定義注解格式:
  public @interface 注解名 {定義體}

  注解參數的可支持數據類型:

    1.所有基本數據類型(int,float,boolean,byte,double,char,long,short)
    2.String類型
    3.Class類型
    4.enum類型
    5.Annotation類型
    6.以上所有類型的數組

  Annotation類型里面的參數該怎么設定: 
  第一,只能用public或默認(default)這兩個訪問權修飾.例如,String value();這里把方法設為defaul默認類型;   
  第二,參數成員只能用基本類型byte,short,char,int,long,float,double,boolean八種基本數據類型和 String,Enum,Class,annotations等數據類型,以及這一些類型的數組.例如,String value();這里的參數成員就為String;  
  第三,如果只有一個參數成員,最好把參數名稱設為"value",后加小括號。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM