1. 程式人生 > >Java Annontation 註解的學習和理解

Java Annontation 註解的學習和理解

/**
 * <html>
 * <body>
 *  <P> Copyright 1994 JsonInternational</p>
 *  <p> All rights reserved.</p>
 *  <p> Created by Jason</p>
 *  </body>
 * </html>
 */
package cn.ucaner.core.annotation;

/**
Annontation是Java5開始引入的新特徵,中文名稱叫註解。
它提供了一種安全的類似註釋的機制,用來將任何的資訊或元資料(metadata)與程式元素(類、方法、成員變數等)進行關聯。
為程式的元素(類、方法、成員變數)加上更直觀更明瞭的說明,這些說明資訊是與程式的業務邏輯無關,並且供指定的工具或框架使用。
Annontation像一種修飾符一樣,應用於包、型別、構造方法、方法、成員變數、引數及本地變數的宣告語句中。
 
Java註解是附加在程式碼中的一些元資訊,用於一些工具在編譯、執行時進行解析和使用,起到說明、配置的功能。
註解不會也不能影響程式碼的實際邏輯,僅僅起到輔助性的作用。
包含在 java.lang.annotation 包中。

常見的用法 :
      1、生成文件。這是最常見的,也是java 最早提供的註解。常用的有
@param @return 等 2、跟蹤程式碼依賴性,實現替代配置檔案功能。比如Dagger 2依賴注入,未來java開發,將大量註解配置,具有很大用處; 3、在編譯時進行格式檢查。如@override 放在方法前,如果你這個方法並不是覆蓋了超類方法,則編譯時就能檢查出。 註解的原理: 註解本質是一個繼承了Annotation的特殊介面,其具體實現類是Java執行時生成的動態代理類。 而我們通過反射獲取註解時,返回的是Java執行時生成的動態代理物件$Proxy1。 通過代理物件呼叫自定義註解(介面)的方法,會最終呼叫AnnotationInvocationHandler的invoke方法。 該方法會從memberValues這個Map中索引出對應的值。 而memberValues的來源是Java常量池。 元註解: @Documented –註解是否將包含在JavaDoc中 @Retention –什麼時候使用該註解 @Target –註解用於什麼地方 @Inherited – 是否允許子類繼承該註解 1.)@Retention– 定義該註解的生命週期 ● RetentionPolicy.SOURCE : 在編譯階段丟棄。 這些註解在編譯結束之後就不再有任何意義,所以它們不會寫入位元組碼。 @Override, @SuppressWarnings都屬於這類註解。 ● RetentionPolicy.CLASS : 在類載入的時候丟棄。在位元組碼檔案的處理中有用。註解預設使用這種方式 ● RetentionPolicy.RUNTIME : 始終不會丟棄,執行期也保留該註解,因此可以使用反射機制讀取該註解的資訊。我們自定義的註解通常使用這種方式。 2.)@Target – 表示該註解用於什麼地方。預設值為任何元素,表示該註解用於什麼地方。可用的ElementType引數包括 ● ElementType.CONSTRUCTOR:用於描述構造器 ● ElementType.FIELD:成員變數、物件、屬性(包括enum例項) ● ElementType.LOCAL_VARIABLE:用於描述區域性變數 ● ElementType.METHOD:用於描述方法 ● ElementType.PACKAGE:用於描述包 ● ElementType.PARAMETER:用於描述引數 ● ElementType.TYPE:用於描述類、介面(包括註解型別) 或enum宣告 3.)@Documented–一個簡單的Annotations標記註解,表示是否將註解資訊新增在java文件中。 4.)@Inherited – 定義該註釋和子類的關係 @Inherited 元註解是一個標記註解,@Inherited闡述了某個被標註的型別是被繼承的。 如果一個使用了@Inherited修飾的annotation型別被用於一個class,則這個annotation將被用於該class的子類。
*/ public class AnnoDefined { }

 

 

 

/**
 * <html>
 * <body>
 *  <P> Copyright 1994 JsonInternational</p>
 *  <p> All rights reserved.</p>
 *  <p> Created on 19941115</p>
 *  <p> Created by Jason</p>
 *  </body>
 * </html>
 
*/ package cn.ucaner.core.annotation; public class AnnoDemo { @FieldMeta(id=true,name="序列號",order=1,description="ID") private int id; @FieldMeta(name="姓名",order=3,description="姓名") private String name; @FieldMeta(name="年齡",order=2) private int age; @FieldMeta(description="描述",order=4) public String desc(){ return "java反射獲取annotation的測試"; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }

 

/**
 * <html>
 * <body>
 *  <P> Copyright 1994 JsonInternational</p>
 *  <p> All rights reserved.</p>
 *  <p> Created by Jason</p>
 *  </body>
 * </html>
 */
package cn.ucaner.core.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* @Package:cn.ucaner.core.annotation   
* @ClassName:FieldMeta   
* @Description:   <p> @FieldMeta  - 註解描述資訊 </p>
* @Author: - Jason   
* @CreatTime:2018年10月18日 下午9:53:45   
* @Modify By:   
* @ModifyTime:  2018年10月18日
* @Modify marker:   
* @version    V1.0
 */
@Retention(RetentionPolicy.RUNTIME) // 註解會在class位元組碼檔案中存在,在執行時可以通過反射獲取到  
@Target({ElementType.FIELD,ElementType.METHOD})//定義註解的作用目標**作用範圍欄位、列舉的常量/方法  
@Documented//說明該註解將被包含在javadoc中  
public @interface FieldMeta {
    
    /** 
     * 是否為序列號 
     * @return 
     */  
    boolean id() default false; 
    
    /** 
     * 欄位名稱 
     * @return 
     */  
    String name() default "default_name";  
    
    /** 
     * 是否可編輯 
     * @return 
     */  
    boolean editable() default true;  
    
    /** 
     * 是否在列表中顯示 
     * @return 
     */  
    boolean summary() default true;  
    
    /** 
     * 欄位描述 
     * @return 
     */  
    String description() default ""; 
    
    /** 
     * 排序欄位 
     * @return 
     */  
    int order() default 0;  

}
/**
 * <html>
 * <body>
 *  <P> Copyright 1994 JsonInternational</p>
 *  <p> All rights reserved.</p>
 *  <p> Created on 19941115</p>
 *  <p> Created by Jason</p>
 *  </body>
 * </html>
 */
package cn.ucaner.core.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/*1.CONSTRUCTOR:用於描述構造器
2.FIELD:用於描述域
3.LOCAL_VARIABLE:用於描述區域性變數
4.METHOD:用於描述方法
5.PACKAGE:用於描述包
6.PARAMETER:用於描述引數
7.TYPE:用於描述類、介面(包括註解型別) 或enum宣告*/

/*(RetentionPoicy)
1.SOURCE:在原始檔中有效(即原始檔保留)
2.CLASS:在class檔案中有效(即class保留)
3.RUNTIME:在執行時有效(即執行時保留)*/

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {
    
    String value() default "Apple";
}
/**
 * <html>
 * <body>
 *  <P> Copyright 1994 JsonInternational</p>
 *  <p> All rights reserved.</p>
 *  <p> Created by Jason</p>
 *  </body>
 * </html>
 */
package cn.ucaner.core.annotation;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;


/**
* @Package:cn.ucaner.core.annotation   
* @ClassName:Parent   
* @Description:   <p> Parent<T> </p>
* @Author: - Jason   
* @CreatTime:2018年10月18日 下午9:54:26   
* @Modify By:   
* @ModifyTime:  2018年10月18日
* @Modify marker:   
* @version    V1.0
 */
public class Parent<T> {
    
    private Class<T> entity;  
      
    public Parent() {  
        init();  
    }  
  
    public List<SortableField> init(){  
        List<SortableField> list = new ArrayList<SortableField>();  
        /**getClass().getGenericSuperclass()返回表示此 Class 所表示的實體(類、介面、基本型別或 void) 
         * 的直接超類的 Type(Class<T>泛型中的型別),然後將其轉換ParameterizedType。。 
         *  getActualTypeArguments()返回表示此型別實際型別引數的 Type 物件的陣列。 
         *  [0]就是這個陣列中第一個了。。 
         *  簡而言之就是獲得超類的泛型引數的實際型別。。*/  
       // entity = (Class<T>)((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];  
//      FieldMeta filed = entity.getAnnotation(FieldMeta.class);  
        this.getClass().getGenericSuperclass();
        //genericSuperclass.
        if(this.entity!=null){  
              
            /**返回類中所有欄位,包括公共、保護、預設(包)訪問和私有欄位,但不包括繼承的欄位 
             * entity.getFields();只返回物件所表示的類或介面的所有可訪問公共欄位 
             * 在class中getDeclared**()方法返回的都是所有訪問許可權的欄位、方法等; 
             * 可看API 
             * */  
            Field[] fields = entity.getDeclaredFields();  
//            
            for(Field f : fields){  
                //獲取欄位中包含fieldMeta的註解  
                FieldMeta meta = f.getAnnotation(FieldMeta.class);  
                if(meta!=null){  
                    SortableField sf = new SortableField(meta, f);  
                    list.add(sf);  
                }  
            }  
              
            //返回物件所表示的類或介面的所有可訪問公共方法  
            Method[] methods = entity.getMethods();  
              
            for(Method m:methods){  
                FieldMeta meta = m.getAnnotation(FieldMeta.class);  
                if(meta!=null){  
                    SortableField sf = new SortableField(meta,m.getName(),m.getReturnType());  
                    list.add(sf);  
                }  
            }  
            //這種方法是新建FieldSortCom類實現Comparator介面,來重寫compare方法實現排序  
//          Collections.sort(list, new FieldSortCom());  
            Collections.sort(list, new Comparator<SortableField>() {  
                @Override  
                public int compare(SortableField s1,SortableField s2) {  
                    return s1.getMeta().order()-s2.getMeta().order();  
//                  return s1.getName().compareTo(s2.getName());//也可以用compare來比較  
                }  
                  
            });  
        }  
        return list;  
          
    }  

}

 

 

/**
 * <html>
 * <body>
 *  <P> Copyright 1994 JsonInternational</p>
 *  <p> All rights reserved.</p>
 *  <p> Created on 19941115</p>
 *  <p> Created by Jason</p>
 *  </body>
 * </html>
 */
package cn.ucaner.core.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* @Package:cn.ucaner.core.annotation   
* @ClassName:SayHiAnnotation   
* @Description:   <p> 自定義註解,用來配置方法</p>
* @Author: - Jason   
* @CreatTime:2018年4月10日 下午9:39:10   
* @Modify By:   
* @ModifyTime:  2018年4月10日
* @Modify marker:   
* @version    V1.0
 */
@Retention(RetentionPolicy.RUNTIME) // 表示註解在執行時依然存在
@Target(ElementType.METHOD) // 表示註解可以被使用於方法上
public @interface SayHiAnnotation {
    
     String paramValue() default "Jason"; 
    // 表示我的註解需要一個引數 名為"paramValue" 預設值為"Jason"
}

 

/**
 * <html>
 * <body>
 *  <P> Copyright 1994 JsonInternational</p>
 *  <p> All rights reserved.</p>
 *  <p> Created on 19941115</p>
 *  <p> Created by Jason</p>
 *  </body>
 * </html>
 */
package cn.ucaner.core.annotation;

/**
* @Package:cn.ucaner.core.annotation   
* @ClassName:SayHiEmlement   
* @Description:   <p> 要使用SayHiAnnotation的元素所在類 </br> 由於我們定義了只有方法才能使用我們的註解,我們就使用多個方法來進行測試</p>
* @Author: - DaoDou   
* @CreatTime:2018年4月10日 下午9:39:49   
* @Modify By:   
* @ModifyTime:  2018年4月10日
* @Modify marker:   
* @version    V1.0
 */
public class SayHiEmlement {

    // 普通的方法
    public void SayHiDefault(String name,String age){
        System.out.println("Hi, " + name+age);
    }
    
    // 使用註解並傳入引數的方法
    @SayHiAnnotation(paramValue="Jack")
    public void SayHiAnnotation(String name,String age){
        System.out.println("Hi, " + name+age);
    }
    
    // 使用註解並使用預設引數的方法
    @SayHiAnnotation
    public void SayHiAnnotationDefault(String name,String age){
        System.out.println("Hi, " + name + age);
    }
}
/**
 * <html>
 * <body>
 *  <P> Copyright 1994 JsonInternational</p>
 *  <p> All rights reserved.</p>
 *  <p> Created by Jason</p>
 *  </body>
 * </html>
 */
package cn.ucaner.core.annotation;

import java.lang.reflect.Field;

/**
* @Package:cn.ucaner.core.annotation   
* @ClassName:SortableField   
* @Description:   <p> SortableField 可排序欄位 </p>
* @Author: - Jason   
* @CreatTime:2018年10月18日 下午9:55:25   
* @Modify By:   
* @ModifyTime:  2018年10月18日
* @Modify marker:   
* @version    V1.0
 */
public class SortableField {
    
    public SortableField(){}  
     
    public SortableField(FieldMeta meta, Field field) {  
        super();  
        this.meta = meta;  
        this.field = field;  
        this.name=field.getName();  
        this.type=field.getType();  
    }  
      
      
    public SortableField(FieldMeta meta, String name, Class<?> type) {  
        super();  
        this.meta = meta;  
        this.name = name;  
        this.type = type;  
    }  
  
  
    private FieldMeta meta;  
    private Field field;  
    private String name;  
    private Class<?> type;  
      
    public FieldMeta getMeta() {  
        return meta;  
    }  
    public void setMeta(FieldMeta meta) {  
        this.meta = meta;  
    }  
    public Field getField() {  
        return field;  
    }  
    public void setField(Field field) {  
        this.field = field;  
    }  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public Class<?> getType() {  
        return type;  
    }  
  
    public void setType(Class<?> type) {  
        this.type = type;  
    }  

}
/**
 * <html>
 * <body>
 *  <P> Copyright 1994 JsonInternational</p>
 *  <p> All rights reserved.</p>
 *  <p> Created by Jason</p>
 *  </body>
 * </html>
 */
package cn.ucaner.core.annotation;

import java.lang.reflect.Field;

/**
* @Package:cn.ucaner.core.annotation   
* @ClassName:TestMain   
* @Description:   <p> TestMain </p>
* @Author: - Jason   
* @CreatTime:2018年10月19日 下午3:17:20   
* @Modify By:   
* @ModifyTime:  2018年10月19日
* @Modify marker:   
* @version    V1.0
 */
public class TestMain {

    @FieldMeta(name="Jason")//註解的使用
    private Object obj;
    
    @FieldMeta(name="Andy",description="Intersting")
    private String name;
    
    @FruitName(value="Apple")
    @FieldMeta
    private String profile;
    
    public String getProfile() {
        return profile;
    }

    public void setProfile(String profile) {
        this.profile = profile;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public Object getObj() {
        return obj;
    }

    public void setObj(Object obj) {
        this.obj = obj;
    }


    /**
     * @Description: Just for test   註解反射的方式拿到元資訊資料
     * @throws Exception void
     */
    public static void main(String[] args) throws Exception{
        
         Field[] fields = TestMain.class.getDeclaredFields();
         for (Field field : fields) {
            System.out.println(field.getName());
             if(field.isAnnotationPresent(FieldMeta.class)){
                 FieldMeta fieldMeta = field.getAnnotation(FieldMeta.class);
                 String str = fieldMeta.name();
                 String description = fieldMeta.description();
                 System.out.println(str);
                 System.out.println(description);
              }if (field.isAnnotationPresent(FruitName.class)) {
                  FruitName fruitName = field.getAnnotation(FruitName.class);
                  System.out.println(fruitName.value());
            }else{
                  //FruitName fruitName = field.getAnnotation(FruitName.class);
                  //System.out.println(fruitName.value());
              }
         }
         
      }

}
//Output
//obj
//Jason
//
//name
//Andy
//Intersting
//profile
//default_name
//
//Apple