深入理解Java:注解(Annotation)自定義注解入門
注解的定義
Java注解又稱Java標注,是JDK5.0版本開始支持加入源代碼的特殊語法元數據。
Java語言中的類、方法、變量、參數和包等都可以被標注。和Javadoc不同,Java標注可以通過反射獲取標注內容。在編譯器生成類文件時,標注可以被嵌入到字節碼中。Java虛擬機可以保留標注內容,在運行時可以獲取到標注內容。 當然它也支持自定義Java標注。
元注解的源碼位置
元注解解析及實例
@Documented
指示某一類型的注釋將通過默認javadoc和類似的工具來記錄。這種類型應該用於注釋類型的注釋影響他們的客戶使用注釋元素的聲明。如果一個類型聲明歸檔的注解,注解它成為注釋元素的公共API的一部分
import java.lang.annotation.*;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Dog {
public String name() default "wangcai";
public int age() default 0;
}
@Inherited
此注解是標識性的元注解,表示當前注解可以由子注解來繼承
import java.lang.annotation.Inherited;
@Inherited
public @interface testInherited {
Sring name();
}
@Target
用於注解類、接口(包括注解類型) 或enum聲明,用逗號分隔隔開來表示作用域。
關鍵代碼
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/**
* Returns an array of the kinds of elements an annotation type
* can be applied to.
* @return an array of the kinds of elements an annotation type
* can be applied to
*/
ElementType[] value();
}
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,
/** Constructor declaration */
/**構造方法的聲明*/
CONSTRUCTOR,
/** Local variable declaration */
/**本地局部變量聲明*/
LOCAL_VARIABLE,
/** Annotation type declaration */
/**注解類型聲明*/
ANNOTATION_TYPE,
/** Package declaration */
/**包聲明*/
PACKAGE,
/**
* Type parameter declaration
*
* @since 1.8
*/
/**參數聲明*
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
/**類型使用*
TYPE_USE
}
@Retention
生命周期注解,表示注解保留的時間長短,被描述的注解在什么范圍內有效
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
/**注釋將被編譯時丟棄*/
SOURCE,
/**
* 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文件中,但VM運行時丟棄*/
CLASS,
/**
* 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
}
自定義注解
定義標記需要使用元注解
- 使用元注解@Target來標記該注解的作用范圍(空間范圍,在哪些地方可以使用)
- 使用元注解@Retention來標記該注解的作用時間范圍(時間范圍,在什么時候起作用)
- 使用元注解@Inherited來標記該注解是否可以由子注解來繼承
- 使用元注解@Documented來標記該注解是否需要自動生成文檔
- 使用@interface關鍵詞來定義注解
- 在注解內部定義一些相關的屬性,一般是方法的形式來定義屬性
自定義注解實例
- 新建自定義注解,這里以idea為例,在想新建注解的位置,鼠標右鍵->New->Java Class
- 選擇想要的方式,添加名稱
- 選擇Annotation,新建一個Food的接口
/**
* 該注解為一個字段注解
* Description:
*
* @author: jieya
* Date: 2021-05-19
* Time: 18:05
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Food {
String name() default "";
}
- 選擇Class,新建一個
/**
* 這里定義了食物的相關注解
* Description:
*
* @author: jieya
* Date: 2021-05-19
* Time: 18:11
*/
public class FoodAnnotation {
// 這里是單獨定義
// @Target(ElementType.FIELD)
// @Retention(RetentionPolicy.RUNTIME)
// public @interface red {
// }
//
// @Target(ElementType.FIELD)
// @Retention(RetentionPolicy.RUNTIME)
// public @interface green {
// }
// 這里使用枚舉類經營定義
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface color {
/**
* 顏色枚舉
*
*/
public enum Color{RED,GREEN};
/**
* 顏色屬性
*/
Color color() default color.Color.GREEN;
}
}
/**
* 定義了一個食物的實體對象類
* Description:
*
* @author: jieya
* Date: 2021-05-19
* Time: 18:34
*/
@Data
@AllArgsConstructor
public class FoodTest {
@Food
@FoodAnnotation.color(color = FoodAnnotation.color.Color.GREEN)
private String bread;
/**
* 飲料不算食物,就不加注解
*/
private String drinks;
@Food
@FoodAnnotation.color(color = FoodAnnotation.color.Color.RED)
private String biscuits;
/**
* 以下為使用反射獲取注解的內容
*
* @param args
*/
public static void main(String[] args) {
// 定義一個食物實體對象
FoodTest food = new FoodTest("桃李面包", "百世", "達利園");
// 獲取類模板
Class c = food.getClass();
// 獲取所有字段
for (Field f : c.getDeclaredFields()) {
// 判斷該字段是否有Food注解
if (f.isAnnotationPresent(Food.class)) {
Food annotation = f.getAnnotation(Food.class);
System.out.println("字段:[" + f.getName() + "]," + "該字段使用了Food注解");
// 判斷該字段是否有color注解
if (f.isAnnotationPresent(FoodAnnotation.color.class)) {
FoodAnnotation.color.Color color = f.getAnnotation(FoodAnnotation.color.class).color();
System.out.println("字段:[" + f.getName() + "]," + "該字段使用了color注解" + "顏色為" + color);
}
} else {
System.out.println("字段:[" + f.getName() + "]," + "該字段沒有使用注解");
}
}
}
}
FIELD注解是最常使用的,其他的注解方法的使用在這里就不在贅述了,都是大同小異的。