注解用于為 Java 代碼提供元數(shù)據(jù)吗氏。一種代碼級(jí)別的說(shuō)明,與類雷逆、接口弦讽、枚舉是在同一個(gè)層次。它可以聲明在包关面、類坦袍、字段、方法等太、局部變量捂齐、方法參數(shù)等的前面,用來(lái)對(duì)這些元素進(jìn)行說(shuō)明缩抡,注釋奠宜。
注解作用:
編寫(xiě)文檔:通過(guò)代碼里標(biāo)識(shí)的注解生成文檔
代碼分析:通過(guò)代碼里標(biāo)識(shí)的注解對(duì)代碼進(jìn)行分析包颁,使用反射
編譯檢查:通過(guò)代碼里標(biāo)識(shí)的注解讓編譯器能夠?qū)崿F(xiàn)基本的編譯檢查,例如:@Override注解
一压真、JDK中預(yù)定義的一些注解
@Deprecated:標(biāo)注已過(guò)時(shí)
@SuppressWarnings(String[] value):壓制警告娩嚼,需要傳參
二、元注解
元注解是描述注解的注解滴肿。
1岳悟、@Target:描述注解能夠作用的位置
@Target的取值:
在@Target注解中使用枚舉ElementType來(lái)表示作用范圍,ElementType有以下幾個(gè)屬性:
TYPE:表示可以作用于類上
FIELD:表示可以作用于字段上泼差,包括枚舉類型
METHOD:表示可以作用于方法上
PARAMETER:表示可以作用于參數(shù)上
CONSTRUCTOR:表示可以作用于構(gòu)造函數(shù)上
LOCAL_VARIABLE:表示可以作用于局部變量上
ANNOTATION_TYPE:表示可以作用于注釋類型上贵少,@Retention注解中就使用該屬性
PACKAGE:表示可以作用于包上
TYPE_PARAMETER:表示可以作用于類型參數(shù),即泛型方法堆缘、泛型類等
TYPE_USE:表示可以作用于類型使用滔灶,可以用于標(biāo)準(zhǔn)任意類型除了class
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {}
2、@Retention:描述注解被保留的階段
@Retention的取值:
在@Retention注解中使用枚舉RetentionPolicy來(lái)表示注解保留時(shí)期吼肥,RetentionPolicy有以下幾個(gè)屬性:
SOURCE:注解僅存在于源碼中录平,在class字節(jié)碼文件中不包含
CLASS:默認(rèn)保留策略,注解會(huì)在class字節(jié)碼文件中存在缀皱,但運(yùn)行時(shí)無(wú)法獲得
RUNTIME:在運(yùn)行時(shí)可以通過(guò)反射獲取到斗这,注解會(huì)在字節(jié)碼文件中存在
自定義注解中肯定要使用@Retention(RetentionPolicy.RUNTIME)
。
3唆鸡、@Documented:描述注解是否被抽取到api文檔中
它的作用是能夠?qū)⒆⒔庵械脑匕絁avadoc中去涝影。
4、@Inherited:描述注解是否被子類繼承
@Inherited
注解了的注解修飾了一個(gè)父類争占,如果他的子類沒(méi)有被其他注解修飾燃逻,則它的子類也繼承了父類的注解。
5臂痕、@Repeatable:描述注解是否可重復(fù)
這個(gè)元注解修飾的注解可以同時(shí)作用一個(gè)對(duì)象多次伯襟,但是每次作用注解又可以代表不同的含義。比如說(shuō)你定義了一個(gè)注解握童,如果你的注解沒(méi)有標(biāo)記@Repeatable這個(gè)JDK自帶的注解姆怪,那么你這個(gè)注解在引用的地方就只能使用一次。
@Repeatable(PersonsAnno.class)
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PersonAnno {
String role() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PersonsAnno {
PersonAnno[] value();
}
public class Test {
@PersonAnno(role = "a")
@PersonAnno(role = "b")
public void test(){}
}
三澡绩、自定義注解
格式:public @interface 注解名稱{}
本質(zhì):注解本質(zhì)上就是一個(gè)接口稽揭,該接口默認(rèn)繼承Annotation
接口
public interface MyAnno extends java.lang.annotation.Annotation{}
/**Annotation接口源碼*/
public interface Annotation {
boolean equals(Object obj);
int hashCode();
String toString();
Class<? extends Annotation> annotationType();
}
注解類型元素:就是注解的屬性,也就是注解中的內(nèi)容肥卡,接口中的抽象方法
-
要求:
- 1溪掀、屬性的返回值類型
- 基本數(shù)據(jù)類型
- String
- 枚舉
- 注解
- 以上類型的數(shù)組
public @interface MyAnno extends java.lang.annotation.Annotation{ String test01(); //void test02(); //void是不可以的 }
- 1溪掀、屬性的返回值類型
- 2、定義了屬性步鉴,在需要時(shí)需要給屬性賦值
- 1揪胃、如果定義屬性時(shí)璃哟,使用default關(guān)鍵字給屬性默認(rèn)初始化值,則使用注解時(shí)喊递,可以不進(jìn)行屬性的賦值
- 2随闪、如果只有一個(gè)屬性需要賦值,并且屬性的名稱是value骚勘,則value可以省略铐伴,直接定義值即可
- 3、數(shù)組賦值時(shí)调鲸,使用大括號(hào)包裹盛杰,如果數(shù)組中只有一個(gè)值,則大括號(hào)可以省略
public @interface MyAnno extends java.lang.annotation.Annotation{
String name() default "aa";
int age();
int sex();
String[] strs();
}
@MyAnno(age = 12,sex = 0,strs={"a","b"})
public void test(){}
四藐石、獲取注解的屬性
使用注解時(shí),使用反射來(lái)獲取注解屬性定拟,獲取注解中定義的屬性值步驟:
1于微、獲取注解定義的位置的對(duì)象(class、Method青自、Field)株依,判斷是否有注解,主要有三個(gè)方法
2延窜、獲取注解的對(duì)象
3恋腕、調(diào)用注解中的抽象方法獲取配置的屬性值
public class CountEntiy {
public void count(){
System.out.println("count執(zhí)行");
}
}
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnoProperties {
String className();
String methodName();
}
//源碼中的方法
//判斷是否存在對(duì)應(yīng)的Annotation對(duì)象
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
return AnnotatedElement.super.isAnnotationPresent(annotationClass);
}
//獲取Annotation對(duì)象
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
Objects.requireNonNull(annotationClass);
return (A) annotationData().annotations.get(annotationClass);
}
//獲取所有Annotation對(duì)象數(shù)組
public Annotation[] getAnnotations() {
return AnnotationParser.toArray(annotationData().annotations);
}
下面例子介紹獲取屬性:
@AnnoProperties(className = "com.test.CountEntiy",methodName = "count")
public class MyAnno {
@AnnoProperties(className = "com.test.CountEntiy",methodName = "count")
public void myAnnoTest(){
System.out.println("myAnnoTest執(zhí)行")
}
}
public class Test {
public static void main(String[] args) throws Exception {
//獲取類注解屬性
//獲取注解定義位置的對(duì)象
Class<Test> clzMyAnno = MyAnno.calss;
//判斷是否有注解
boolean testPresent = clzMyAnno.isAnnotationPresent(AnnoProperties.class);
if(testPresent) {
//獲取注解的對(duì)象
AnnoProperties anno = clzMyAnno.getAnnotation(AnnoProperties.class);
//調(diào)用注解中的抽象方法獲取配置的屬性值
String className = anno.className();
String methodName = anno.methodName();
}
//獲取方法MyAnno.calss.get注解屬性
Method method = MyAnno.calss.getDeclaredMethod("myAnnoTest");
boolean methodPresent = method.isAnnotationPresent(AnnoProperties.class);
if(methodPresent) {
AnnoProperties annoPro = method.getAnnotation(AnnoProperties.class);
String className = anno.className();
String methodName = anno.methodName();
}
//用反射執(zhí)行myAnnoTest()方法
Class clz = Class.forName(className);
Object obj = clz.newInstance();
Method method = clz.getMethod(methodName);
method.invoke(obj);
}
}
//結(jié)果:myAnnoTest執(zhí)行