Java Annontation 註解的學習和理解
阿新 • • 發佈:2018-11-09
/** * <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