java 注解默認(rèn)值操作
我就廢話不多說(shuō)了,大家還是直接看代碼吧~
package com.zejian.annotationdemo; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Created by wuzejian on 2017/5/19. * 數(shù)據(jù)類型使用Demo */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface Reference{ boolean next() default false; } public @interface AnnotationElementDemo { //枚舉類型 enum Status {FIXED,NORMAL}; //聲明枚舉 Status status() default Status.FIXED; //布爾類型 boolean showSupport() default false; //String類型 String name()default ""; //class類型 Class<?> testCase() default Void.class; //注解嵌套 Reference reference() default @Reference(next=true); //數(shù)組類型 long[] value(); }
補(bǔ)充:Java自定義注解中關(guān)于string[] value() default {};的理解
java自定義注解
Java注解是附加在代碼中的一些元信息,用于一些工具在編譯、運(yùn)行時(shí)進(jìn)行解析和使用,起到說(shuō)明、配置的功能。
注解不會(huì)也不能影響代碼的實(shí)際邏輯,僅僅起到輔助性的作用。包含在 java.lang.annotation 包中。
1、元注解
元注解是指注解的注解。包括 @Retention @Target @Document @Inherited四種。
1.1、@Retention: 定義注解的保留策略
@Retention(RetentionPolicy.SOURCE) //注解僅存在于源碼中,在class字節(jié)碼文件中不包含 @Retention(RetentionPolicy.CLASS) // 默認(rèn)的保留策略,注解會(huì)在class字節(jié)碼文件中存在,但運(yùn)行時(shí)無(wú)法獲得, @Retention(RetentionPolicy.RUNTIME) // 注解會(huì)在class字節(jié)碼文件中存在,在運(yùn)行時(shí)可以通過(guò)反射獲取到
注解類:
@Retention(RetentionPolicy.RUNTIME) // 注解會(huì)在class字節(jié)碼文件中存在,在運(yùn)行時(shí)可以通過(guò)反射獲取到 @Target({ElementType.FIELD,ElementType.METHOD})//定義注解的作用目標(biāo)**作用范圍字段、枚舉的常量/方法 @Documented//說(shuō)明該注解將被包含在javadoc中 public @interface FieldMeta { /** * 是否為序列號(hào) * @return */ boolean id() default false; /** * 字段名稱 * @return */ String name() default ""; /** * 是否可編輯 * @return */ boolean editable() default true; /** * 是否在列表中顯示 * @return */ boolean summary() default true; /** * 字段描述 * @return */ String description() default ""; /** * 排序字段 * @return */ int order() default 0; }
實(shí)體類:
public class Anno { @FieldMeta(id=true,name="序列號(hào)",order=1) private int id; @FieldMeta(name="姓名",order=3) private String name; @FieldMeta(name="年齡",order=2) private int age; @FieldMeta(description="描述",order=4) public String desc(){ return "java反射獲取annotation的測(cè)試"; } 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; } }
獲取到注解的幫助類:
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; } }
運(yùn)行時(shí)獲取注解,首先創(chuàng)建一個(gè)基類:
public class Parent<T> { private Class<T> entity; public Parent() { init(); } @SuppressWarnings("unchecked") public List<SortableField> init(){ List<SortableField> list = new ArrayList<SortableField>(); /**getClass().getGenericSuperclass()返回表示此 Class 所表示的實(shí)體(類、接口、基本類型或 void) * 的直接超類的 Type(Class<T>泛型中的類型),然后將其轉(zhuǎn)換ParameterizedType。。 * getActualTypeArguments()返回表示此類型實(shí)際類型參數(shù)的 Type 對(duì)象的數(shù)組。 * [0]就是這個(gè)數(shù)組中第一個(gè)了。。 * 簡(jiǎn)而言之就是獲得超類的泛型參數(shù)的實(shí)際類型。。*/ entity = (Class<T>)((ParameterizedType)this.getClass().getGenericSuperclass()) .getActualTypeArguments()[0]; // FieldMeta filed = entity.getAnnotation(FieldMeta.class); if(this.entity!=null){ /**返回類中所有字段,包括公共、保護(hù)、默認(rèn)(包)訪問(wèn)和私有字段,但不包括繼承的字段 * entity.getFields();只返回對(duì)象所表示的類或接口的所有可訪問(wèn)公共字段 * 在class中g(shù)etDeclared**()方法返回的都是所有訪問(wèn)權(quán)限的字段、方法等; * 可看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); } } //返回對(duì)象所表示的類或接口的所有可訪問(wèn)公共方法 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類實(shí)現(xiàn)Comparator接口,來(lái)重寫compare方法實(shí)現(xiàn)排序 // 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來(lái)比較 } }); } return list; } }
創(chuàng)建子類繼承基類:
public class Child extends Parent<Anno>{ }
測(cè)試類:
public class TestAnnotation { @SuppressWarnings({ "unchecked", "rawtypes" }) public static void main(String[] args) { Parent c = new Child(); List<SortableField> list = c.init();//獲取泛型中類里面的注解 //輸出結(jié)果 for(SortableField l : list){ System.out.println("字段名稱:"+l.getName()+"\t字段類型:"+l.getType()+ "\t注解名稱:"+l.getMeta().name()+"\t注解描述:"+l.getMeta().description()); } } }
1、Annotation的工作原理:
JDK5.0中提供了注解的功能,允許開(kāi)發(fā)者定義和使用自己的注解類型。該功能由一個(gè)定義注解類型的語(yǔ)法和描述一個(gè)注解聲明的語(yǔ)法,讀取注解的API,一個(gè)使用注解修飾的class文件和一個(gè)注解處理工具組成。
Annotation并不直接影響代碼的語(yǔ)義,但是他可以被看做是程序的工具或者類庫(kù)。它會(huì)反過(guò)來(lái)對(duì)正在運(yùn)行的程序語(yǔ)義有所影響。
Annotation可以沖源文件、class文件或者在運(yùn)行時(shí)通過(guò)反射機(jī)制多種方式被讀取。
2、@Override注解:
java.lang
注釋類型 Override
@Target(value=METHOD) @Retention(value=SOURCE) public @interface Override
表示一個(gè)方法聲明打算重寫超類中的另一個(gè)方法聲明。如果方法利用此注釋類型進(jìn)行注解但沒(méi)有重寫超類方法,則編譯器會(huì)生成一條錯(cuò)誤消息。
@Override注解表示子類要重寫父類的對(duì)應(yīng)方法。
Override是一個(gè)Marker annotation,用于標(biāo)識(shí)的Annotation,Annotation名稱本身表示了要給工具程序的信息。
下面是一個(gè)使用@Override注解的例子:
class A { private String id; A(String id){ this.id = id; } @Override public String toString() { return id; } }
3、@Deprecated注解:
java.lang
注釋類型 Deprecated
@Documented @Retention(value=RUNTIME) public @interface Deprecated
用 @Deprecated 注釋的程序元素,不鼓勵(lì)程序員使用這樣的元素,通常是因?yàn)樗芪kU(xiǎn)或存在更好的選擇。在使用不被贊成的程序元素或在不被贊成的代碼中執(zhí)行重寫時(shí),編譯器會(huì)發(fā)出警告。
@Deprecated注解表示方法是不被建議使用的。
Deprecated是一個(gè)Marker annotation。
下面是一個(gè)使用@Deprecated注解的例子:
class A { private String id; A(String id){ this.id = id; } @Deprecated public void execute(){ System.out.println(id); } public static void main(String[] args) { A a = new A("a123"); a.execute(); } }
4、@SuppressWarnings注解:
java.lang
注釋類型 SuppressWarnings
@Target(value={TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE}) @Retention(value=SOURCE) public @interface SuppressWarnings
指示應(yīng)該在注釋元素(以及包含在該注釋元素中的所有程序元素)中取消顯示指定的編譯器警告。注意,在給定元素中取消顯示的警告集是所有包含元素中取消顯示的警告的超集。例如,如果注釋一個(gè)類來(lái)取消顯示某個(gè)警告,同時(shí)注釋一個(gè)方法來(lái)取消顯示另一個(gè)警告,那么將在此方法中同時(shí)取消顯示這兩個(gè)警告。
根據(jù)風(fēng)格不同,程序員應(yīng)該始終在最里層的嵌套元素上使用此注釋,在那里使用才有效。如果要在特定的方法中取消顯示某個(gè)警告,則應(yīng)該注釋該方法而不是注釋它的類。
@SuppressWarnings注解表示抑制警告。
下面是一個(gè)使用@SuppressWarnings注解的例子:
@SuppressWarnings("unchecked") public static void main(String[] args) { List list = new ArrayList(); list.add("abc"); }
5、自定義注解:
使用@interface自定義注解時(shí),自動(dòng)繼承了java.lang.annotation.Annotation接口,由編譯程序自動(dòng)完成其他細(xì)節(jié)。在定義注解時(shí),不能繼承其他的注解或接口。
自定義最簡(jiǎn)單的注解:
public @interface MyAnnotation { }
使用自定義注解:
public class AnnotationTest2 { @MyAnnotation public void execute(){ System.out.println("method"); } }
5.1、添加變量:
public @interface MyAnnotation { String value1(); }
使用自定義注解:
public class AnnotationTest2 { @MyAnnotation(value1="abc") public void execute(){ System.out.println("method"); } }
當(dāng)注解中使用的屬性名為value時(shí),對(duì)其賦值時(shí)可以不指定屬性的名稱而直接寫上屬性值接口;除了value意外的變量名都需要使用name=value的方式賦值。
5.2、添加默認(rèn)值:
public @interface MyAnnotation { String value1() default "abc"; }
5.3、多變量使用枚舉:
public @interface MyAnnotation { String value1() default "abc"; MyEnum value2() default MyEnum.Sunny; } enum MyEnum{ Sunny,Rainy }
使用自定義注解:
public class AnnotationTest2 { @MyAnnotation(value1="a", value2=MyEnum.Sunny) public void execute(){ System.out.println("method"); } }
5.4、數(shù)組變量:
public @interface MyAnnotation { String[] value1() default "abc"; }
使用自定義注解:
public class AnnotationTest2 { @MyAnnotation(value1={"a","b"}) public void execute(){ System.out.println("method"); } }
6、設(shè)置注解的作用范圍:
@Documented @Retention(value=RUNTIME) @Target(value=ANNOTATION_TYPE) public @interface Retention
指示注釋類型的注釋要保留多久。如果注釋類型聲明中不存在 Retention 注釋,則保留策略默認(rèn)為 RetentionPolicy.CLASS。
只有元注釋類型直接用于注釋時(shí),Target 元注釋才有效。如果元注釋類型用作另一種注釋類型的成員,則無(wú)效。
public enum RetentionPolicy
extends Enum<RetentionPolicy>
注釋保留策略。此枚舉類型的常量描述保留注釋的不同策略。它們與 Retention 元注釋類型一起使用,以指定保留多長(zhǎng)的注釋。
CLASS
編譯器將把注釋記錄在類文件中,但在運(yùn)行時(shí) VM 不需要保留注釋。
RUNTIME
編譯器將把注釋記錄在類文件中,在運(yùn)行時(shí) VM 將保留注釋,因此可以反射性地讀取。
SOURCE
編譯器要丟棄的注釋。
@Retention注解可以在定義注解時(shí)為編譯程序提供注解的保留策略。
屬于CLASS保留策略的注解有@SuppressWarnings,該注解信息不會(huì)存儲(chǔ)于.class文件。
6.1、在自定義注解中的使用例子:
@Retention(RetentionPolicy.CLASS) public @interface MyAnnotation { String[] value1() default "abc"; }
7、使用反射讀取RUNTIME保留策略的Annotation信息的例子:
java.lang.reflect
接口 AnnotatedElement
所有已知實(shí)現(xiàn)類:
AccessibleObject, Class, Constructor, Field, Method, Package
表示目前正在此 VM 中運(yùn)行的程序的一個(gè)已注釋元素。該接口允許反射性地讀取注釋。由此接口中的方法返回的所有注釋都是不可變并且可序列化的。調(diào)用者可以修改已賦值數(shù)組枚舉成員的訪問(wèn)器返回的數(shù)組;這不會(huì)對(duì)其他調(diào)用者返回的數(shù)組產(chǎn)生任何影響。
如果此接口中的方法返回的注釋(直接或間接地)包含一個(gè)已賦值的 Class 成員,該成員引用了一個(gè)在此 VM 中不可訪問(wèn)的類,則試圖通過(guò)在返回的注釋上調(diào)用相關(guān)的類返回的方法來(lái)讀取該類,將導(dǎo)致一個(gè) TypeNotPresentException。
isAnnotationPresent
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
如果指定類型的注釋存在于此元素上,則返回 true,否則返回 false。此方法主要是為了便于訪問(wèn)標(biāo)記注釋而設(shè)計(jì)的。
參數(shù):
annotationClass - 對(duì)應(yīng)于注釋類型的 Class 對(duì)象
返回:
如果指定注釋類型的注釋存在于此對(duì)象上,則返回 true,否則返回 false
拋出:
NullPointerException - 如果給定的注釋類為 null
從以下版本開(kāi)始:
1.5
getAnnotation
<T extends Annotation> T getAnnotation(Class<T> annotationClass)
如果存在該元素的指定類型的注釋,則返回這些注釋,否則返回 null。
參數(shù):
annotationClass - 對(duì)應(yīng)于注釋類型的 Class 對(duì)象
返回:
如果該元素的指定注釋類型的注釋存在于此對(duì)象上,則返回這些注釋,否則返回 null
拋出:
NullPointerException - 如果給定的注釋類為 null
從以下版本開(kāi)始:
1.5
getAnnotations
Annotation[] getAnnotations()
返回此元素上存在的所有注釋。(如果此元素沒(méi)有注釋,則返回長(zhǎng)度為零的數(shù)組。)該方法的調(diào)用者可以隨意修改返回的數(shù)組;這不會(huì)對(duì)其他調(diào)用者返回的數(shù)組產(chǎn)生任何影響。
返回:
此元素上存在的所有注釋
從以下版本開(kāi)始:
1.5
getDeclaredAnnotations
Annotation[] getDeclaredAnnotations()
返回直接存在于此元素上的所有注釋。與此接口中的其他方法不同,該方法將忽略繼承的注釋。(如果沒(méi)有注釋直接存在于此元素上,則返回長(zhǎng)度為零的一個(gè)數(shù)組。)該方法的調(diào)用者可以隨意修改返回的數(shù)組;這不會(huì)對(duì)其他調(diào)用者返回的數(shù)組產(chǎn)生任何影響。
返回:
直接存在于此元素上的所有注釋
從以下版本開(kāi)始:
1.5
下面是使用反射讀取RUNTIME保留策略的Annotation信息的例子:
自定義注解:
@Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { String[] value1() default "abc"; }
使用自定義注解:
public class AnnotationTest2 { @MyAnnotation(value1={"a","b"}) @Deprecated public void execute(){ System.out.println("method"); } }
讀取注解中的信息:
public static void main(String[] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { AnnotationTest2 annotationTest2 = new AnnotationTest2(); //獲取AnnotationTest2的Class實(shí)例 Class<AnnotationTest2> c = AnnotationTest2.class; //獲取需要處理的方法Method實(shí)例 Method method = c.getMethod("execute", new Class[]{}); //判斷該方法是否包含MyAnnotation注解 if(method.isAnnotationPresent(MyAnnotation.class)){ //獲取該方法的MyAnnotation注解實(shí)例 MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class); //執(zhí)行該方法 method.invoke(annotationTest2, new Object[]{}); //獲取myAnnotation String[] value1 = myAnnotation.value1(); System.out.println(value1[0]); } //獲取方法上的所有注解 Annotation[] annotations = method.getAnnotations(); for(Annotation annotation : annotations){ System.out.println(annotation); } }
8、限定注解的使用:
限定注解使用@Target。
@Documented @Retention(value=RUNTIME) @Target(value=ANNOTATION_TYPE) public @interface Target
指示注釋類型所適用的程序元素的種類。如果注釋類型聲明中不存在 Target 元注釋,則聲明的類型可以用在任一程序元素上。如果存在這樣的元注釋,則編譯器強(qiáng)制實(shí)施指定的使用限制。 例如,此元注釋指示該聲明類型是其自身,即元注釋類型。它只能用在注釋類型聲明上:
@Target(ElementType.ANNOTATION_TYPE) public @interface MetaAnnotationType { ... }
此元注釋指示該聲明類型只可作為復(fù)雜注釋類型聲明中的成員類型使用。它不能直接用于注釋:
@Target({}) public @interface MemberType { ... }
這是一個(gè)編譯時(shí)錯(cuò)誤,它表明一個(gè) ElementType 常量在 Target 注釋中出現(xiàn)了不只一次。例如,以下元注釋是非法的:
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.FIELD}) public @interface Bogus { ... } public enum ElementType extends Enum<ElementType>
程序元素類型。此枚舉類型的常量提供了 Java 程序中聲明的元素的簡(jiǎn)單分類。
這些常量與 Target 元注釋類型一起使用,以指定在什么情況下使用注釋類型是合法的。
ANNOTATION_TYPE
注釋類型聲明
CONSTRUCTOR
構(gòu)造方法聲明
FIELD
字段聲明(包括枚舉常量)
LOCAL_VARIABLE
局部變量聲明
METHOD
方法聲明
PACKAGE
包聲明
PARAMETER
參數(shù)聲明
TYPE
類、接口(包括注釋類型)或枚舉聲明
注解的使用限定的例子:
@Target(ElementType.METHOD) public @interface MyAnnotation { String[] value1() default "abc"; }
9、在幫助文檔中加入注解:
要想在制作JavaDoc文件的同時(shí)將注解信息加入到API文件中,可以使用java.lang.annotation.Documented。
在自定義注解中聲明構(gòu)建注解文檔:
@Documented public @interface MyAnnotation { String[] value1() default "abc"; }
使用自定義注解:
public class AnnotationTest2 { @MyAnnotation(value1={"a","b"}) public void execute(){ System.out.println("method"); } }
10、在注解中使用繼承:
默認(rèn)情況下注解并不會(huì)被繼承到子類中,可以在自定義注解時(shí)加上java.lang.annotation.Inherited注解聲明使用繼承。
@Documented @Retention(value=RUNTIME) @Target(value=ANNOTATION_TYPE) public @interface Inherited
指示注釋類型被自動(dòng)繼承。如果在注釋類型聲明中存在 Inherited 元注釋,并且用戶在某一類聲明中查詢?cè)撟⑨岊愋?,同時(shí)該類聲明中沒(méi)有此類型的注釋,則將在該類的超類中自動(dòng)查詢?cè)撟⑨岊愋?。此過(guò)程會(huì)重復(fù)進(jìn)行,直到找到此類型的注釋或到達(dá)了該類層次結(jié)構(gòu)的頂層 (Object) 為止。如果沒(méi)有超類具有該類型的注釋,則查詢將指示當(dāng)前類沒(méi)有這樣的注釋。
注意,如果使用注釋類型注釋類以外的任何事物,此元注釋類型都是無(wú)效的。還要注意,此元注釋僅促成從超類繼承注釋;對(duì)已實(shí)現(xiàn)接口的注釋無(wú)效。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。
相關(guān)文章
Mybatis-plus:${ew.sqlselect}用法說(shuō)明
這篇文章主要介紹了Mybatis-plus:${ew.sqlselect}用法說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06解決MyEclipse6.5無(wú)法啟動(dòng),一直停留剛開(kāi)始啟動(dòng)界面的詳解
本篇文章是對(duì)解決MyEclipse6.5無(wú)法啟動(dòng),一直停留剛開(kāi)始啟動(dòng)界面的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05Java 實(shí)現(xiàn)并發(fā)的幾種方式小結(jié)
這篇文章主要介紹了Java 實(shí)現(xiàn)并發(fā)的幾種方式小結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-05-05Mybatis攔截器注解@Intercepts與@Signature注解使用
本文主要介紹了Mybatis攔截器注解@Intercepts與@Signature注解使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-07-07詳解Spring Kafka中關(guān)于Kafka的配置參數(shù)
這篇文章主要介紹了詳解Spring Kafka中關(guān)于Kafka的配置參數(shù),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08從dubbo zookeeper注冊(cè)地址提取出zookeeper地址的方法
今天小編就為大家分享一篇關(guān)于從dubbo zookeeper注冊(cè)地址提取出zookeeper地址的方法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-12-12詳解Java編程中protected修飾符與static修飾符的作用
這篇文章主要介紹了Java編程中protected關(guān)鍵字與static關(guān)鍵字的作用,是Java入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2016-01-01