Java之注解.png
Java 注解用于為 Java 代碼提供元數(shù)據(jù)茶袒。作為元數(shù)據(jù)划鸽,注解并不會直接影響你的代碼執(zhí)行冗恨。
1. 注解的定義
注解的定義與類的定義有些類似,只是將class換成@interfacexiu即可
public @interface AnnoTest {
}
但僅僅被
@interface
修飾還不夠檩淋,一個完整的自定義注解還需要配合元注解使用芬为。所以還先需要了解元注解是什么萄金?怎么使用蟀悦?
2. 注解分類
- JDK自帶注解:@Override、@Deprecated氧敢、@SuppressWarning
- 元注解:@Target日戈、@Retention、@Inherited孙乖、@Documented
- 自定義注解
2.1 JDK自帶注解
-
@Override
:表示為被重寫的方法 -
@Deprecated
:表示過時的方法 -
@SuppressWarning
:表示忽略警告
2.2 元注解
用來標記注解的注解
@Target
表示注解的作用域浙炼,通過枚舉類
ElementType
表達作用類型份氧,可以是類,方法弯屈,方法參數(shù)變量等蜗帜。
其中枚舉類ElementType
的取值如下:
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
TYPE, // 作用于接口、類资厉、枚舉厅缺、注解
/** Field declaration (includes enum constants) */
FIELD, // 作用于字段、枚舉的常量
/** Method declaration */
METHOD, // 作用于方法
/** Formal parameter declaration */
PARAMETER, // 作用于方法參數(shù)
/** Constructor declaration */
CONSTRUCTOR, // 作用于構(gòu)造方法
/** Local variable declaration */
LOCAL_VARIABLE, // 作用于局部變量
/** Annotation type declaration */
ANNOTATION_TYPE, // 作用于注解(@Retention注解中就使用該屬性)
/** Package declaration */
PACKAGE, // 作用于包
/**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER, // 作用于類型泛型宴偿,即泛型方法湘捎、泛型類、泛型接口 (jdk1.8加入)
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE
}
@Retention
表示注解存在的生命周期窄刘。注解存在階段是保留在源碼(編譯期)窥妇,字節(jié)碼(類加載)或者運行期(JVM中運行)。通過枚舉類
RetentionPolicy
來表示注解保留時期娩践。
其中枚舉類RetentionPolicy
的取值如下:
public enum RetentionPolicy {
/**
* 注解只存在源碼中,編譯時會丟棄
* Annotations are to be discarded by the compiler.
*/
SOURCE,
/**
* 默認的保留策略活翩,注解會在class字節(jié)碼文件中存在,但運行時無法獲得
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
CLASS,
/**
* 注解會在class字節(jié)碼文件中存在翻伺,在運行時可以通過反射獲取到
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
@Documented
它的作用是能夠?qū)⒆⒔庵械脑匕?Javadoc 中去纱新。
@Inherited
一個被
@Inherited
注解了的注解修飾了一個父類,如果他的子類沒有被其他注解修飾穆趴,則它的子類也繼承了父類的注解脸爱。
2.3 自定義注解(后面講解)
3. 注解的作用
- 標記,用于告訴編譯器的一些信息
- 編譯時動態(tài)處理未妹,如動態(tài)生成代碼
- 運行時動態(tài)處理簿废,如得到注解信息
4. 自定義注解并解析注解
4.1 自定義注解
- 使用@interface關(guān)鍵字定義注解
- 成員以無參無異常的方式聲明
- 可以用default為成員指定默認值
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface AnnoTest { // 使用@interface關(guān)鍵字定義注解
//成員以無參無異常的方式聲明
String desc();
String author();
//可以用default為成員指定默認值
int age() default 18;
}
4.2 注解的屬性類型
- 基本數(shù)據(jù)類型
- String類型
- 枚舉類型
- 注解類型
- Class類型
- 以上類型的數(shù)組類型
4.3 使用注解
注解屬性賦值:如果注解有多個屬性,則可以在注解括號中用“,”號隔開分別給對應(yīng)的屬性賦值
@AnnoTest(desc="annotation class desc", author="annotation class author",age=20)
public class AnnoTestDemo {
@AnnoTest(desc="annotation method desc", author="annotation method author",age=30)
public String test() {
return "test";
}
}
4.4 解析注解
注:如果我們在定義自己的注解的時候,將@Retention(RetentionPolicy.RUNTIME)改為@Retention(RetentionPolicy.SOURCE)或者@Retention(RetentionPolicy.CLASS),運行上面的程序是不會出現(xiàn)任何結(jié)果络它,因為只有運行時注解可以通過反射獲取,其他兩種注解在運行時已經(jīng)被丟棄了族檬。
public static void main(String[] args) {
try {
//1、使用類加載器加載類
Class<?> c = Class.forName("com.anno.AnnoTestDemo");
//2化戳、找到類上面的注解
//先判斷AnnTestDemo類上面有沒有AnnoTest這樣的注解
boolean isExist = c.isAnnotationPresent(AnnoTest.class);
if (isExist) {
//3单料、獲取類上的注解實例
AnnoTest classAnno = (AnnoTest) c.getAnnotation(AnnoTest.class);
System.out.println(classAnno.author());
}
//4、找到方法上的注解
//拿到給定類所包含的方法
Method[] methods = c.getDeclaredMethods();
//遍歷方法
for (Method method : methods) {
boolean isMExist = method.isAnnotationPresent(AnnoTest.class);
if (isMExist) {
//拿到每個方法上的注解
AnnoTest methodAnno = method.getAnnotation(AnnoTest.class);
System.out.println(methodAnno.author());
}
}
//另外一種解析方法上注解的方式
//遍歷所有的方法
for (Method method : methods) {
//拿到每個方法上的注解
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation instanceof AnnoTest) {
AnnoTest methodAnno = (AnnoTest) annotation;
System.out.println(methodAnno.author());
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}