元資訊
Java 注解(Annotation)又稱 Java 標注,是 JDK5.0 引入的一種注釋機制,
Java 語言中的類、方法、變數、引數和包等都可以被標注,和 Javadoc 不同,Java 標注可以通過反射獲取標注內容,在編譯器生成類檔案時,標注可以被嵌入到位元組碼中,Java 虛擬機可以保留標注內容,在運行時可以獲取到標注內容 , 當然它也支持自定義 Java 標注,
由于jdk和框架大量使用注解,我也簡單介紹下注解為何物,若您發現文章中存在錯誤或不足的地方,希望您能指出!
Java 定義了一套注解,共有 7 個,3 個在 java.lang 中,剩下 4 個在 java.lang.annotation 中,
作用在代碼的注解是
- @Override - 檢查該方法是否是重寫方法,如果發現其父類,或者是參考的介面中并沒有該方法時,會報編譯錯誤,
- @Deprecated - 標記過時方法,如果使用該方法,會報編譯警告,
- @SuppressWarnings - 指示編譯器去忽略注解中宣告的警告,
作用在其他注解的注解(或者說 元注解)是:
- @Retention - 標識這個注解怎么保存,是只在代碼中,還是編入class檔案中,或者是在運行時可以通過反射訪問,
- @Documented - 標記這些注解是否包含在用戶檔案中,
- @Target - 標記這個注解應該是哪種 Java 成員,
- @Inherited - 標記這個注解是繼承于哪個注解類(默認 注解并沒有繼承于任何子類)

?
從 Java 7 開始,額外添加了 3 個注解:
- @SafeVarargs - Java 7 開始支持,忽略任何使用引數為泛型變數的方法或建構式呼叫產生的警告,
- @FunctionalInterface - Java 8 開始支持,標識一個匿名函式或函式式介面,
- @Repeatable - Java 8 開始支持,標識某注解可以在同一個宣告上使用多次,
Annotation 架構圖如下:

?
Annotation 的每一個實作類,都 和 1 個 RetentionPolicy 關聯, 和 1~n 個 ElementType 關聯,
注意RetentionPolicy的三種策略,自定義注解需要設定策略
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.
* VM將在運行期也保留注釋,因此可以通過反射機制讀取注解的資訊
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
注意ElementType,自定義注解時特別關注,有多種型別
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration
類,介面(包括注解型別)或enum宣告*/
TYPE,
/** Field declaration (includes enum constants)
域宣告(包括 enum 實體)*/
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
}
下面是個小例子:
自定義注解:
@Documented
@Target({ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnnotation {
public String name() default "";
public String value() default "";
}
在類中使用
/**
* @author dgm
* @describe ""
*/
@CustomAnnotation(name="Class Annotation", value = https://www.cnblogs.com/dongguangming/p/" 類上的注解")
public class SampleClass {
@CustomAnnotation(name = "field Annotation", value = https://www.cnblogs.com/dongguangming/p/"欄位上的注解")
public String sampleField;
@CustomAnnotation(name = "constructor Annotation", value = https://www.cnblogs.com/dongguangming/p/"構造器上的注解")
public SampleClass(String sampleField) {
super();
this.sampleField = sampleField;
}
@CustomAnnotation(name = "Method Annotation getSampleField", value = https://www.cnblogs.com/dongguangming/p/"getSampleField無參方法上的注解")
public String getSampleField() {
System.out.println("getSampleField");
return sampleField;
}
@CustomAnnotation(name = "Method Annotation setSampleField", value = https://www.cnblogs.com/dongguangming/p/"setSampleField方法上的注解")
public void setSampleField(String sampleField) {
System.out.println("setSampleField=" + sampleField);
this.sampleField = sampleField;
}
@CustomAnnotation(name = "Method Annotation getSampleField hava param", value = https://www.cnblogs.com/dongguangming/p/"getSampleField有參方法上的注解")
private String getSampleField(String sampleField) {
return sampleField;
}
}
測驗類
[] publicConstructors = c0.getConstructors();//getDeclaredConstructors\n\n\t for (Constructor constructor : publicConstructors) {\n\t\t\tAnnotation[] methodAnnotation = constructor.getAnnotations();\n\t\t\tfor (Annotation ma : methodAnnotation) {\n\t\t\t\tif (ma instanceof CustomAnnotation) {\n\t\t\t\t\tCustomAnnotation customAnnotation = (CustomAnnotation) ma;\n\t\t\t\t\tSystem.out.println(\"構造器 name: \"\n\t\t\t\t\t\t\t+ customAnnotation.name());\n\t\t\t\t\tSystem.out.println(\"構造器 value: \"\n\t\t\t\t\t\t\t+ customAnnotation.value());\n\n\t\t\t\t}\n\t\t\t}\n\t }\n\t \n\t\t// 獲取類的公有方法\n\t\tMethod[] methods = c0.getMethods();\n\t\t// Annotation annotation =\n\t\t// methods[1].getAnnotation(CustomAnnotation.class);\n\t\tfor (Method method : methods) {\n\t\t\tAnnotation[] methodAnnotation = method.getAnnotations();\n\t\t\tfor (Annotation ma : methodAnnotation) {\n\t\t\t\tif (ma instanceof CustomAnnotation) {\n\t\t\t\t\tCustomAnnotation customAnnotation = (CustomAnnotation) ma;\n\t\t\t\t\tSystem.out.println(\"method name: \"\n\t\t\t\t\t\t\t+ customAnnotation.name());\n\t\t\t\t\tSystem.out.println(\"method value: \"\n\t\t\t\t\t\t\t+ customAnnotation.value());\n\n\t\t\t\t}\n\t\t\t}\n // 獲取方法上的所有引數注解 \n Annotation[][] parameterAnnotations = method.getParameterAnnotations();\n for(Annotation[] pa : parameterAnnotations){\n for(Annotation a:pa){\n if(a instanceof CustomAnnotation){\n System.out.println(\"method param name: \"\n \t\t\t\t\t\t\t+ ((CustomAnnotation) a).name());\n \t\t\t\t\tSystem.out.println(\"method param value: \"\n \t\t\t\t\t\t\t+ ((CustomAnnotation) a).value());\n }\n }\n }\n\n\t\t}\n\t }\n}","classes":[]}" data-cke-widget-upcasted="1" data-cke-widget-keep-attr="0" data-widget="codeSnippet">/**
*
* @author dgm
* @describe ""
*/
public class CustomAnnotationTest {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class c0 = SampleClass.class;
Class c1 = Class.forName("spring.annotation.SampleClass");
Object o = null;
try {
o = Class.forName("spring.annotation.SampleClass").getConstructor(String.class).newInstance("dongguangming");
} catch (NoSuchMethodException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Class c2 = o.getClass();
System.out.println(c0 == c1);
System.out.println(c0 == c2);
System.out.println(c1 == c2);
// 獲取類的所有注解
Annotation[] classAnnotation = c0.getAnnotations();
for (Annotation ca : classAnnotation) {
if (ca instanceof CustomAnnotation) {
CustomAnnotation customAnnotation = (CustomAnnotation) ca;
System.out.println("class name: " + customAnnotation.name());
System.out.println("class value: " + customAnnotation.value());
}
}
// 獲取類的公有field
Field[] fields = c0.getFields();
for (Field field : fields) {
Annotation[] fieldAnnotation = field.getAnnotations();
for (Annotation fa : fieldAnnotation) {
if (fa instanceof CustomAnnotation) {
CustomAnnotation customAnnotation = (CustomAnnotation) fa;
System.out
.println("field name: " + customAnnotation.name());
System.out.println("field value: "
+ customAnnotation.value());
}
}
}
// 獲取構造器的所有注解
// 獲取類的構造器
Constructor<?>[] publicConstructors = c0.getConstructors();//getDeclaredConstructors
for (Constructor constructor : publicConstructors) {
Annotation[] methodAnnotation = constructor.getAnnotations();
for (Annotation ma : methodAnnotation) {
if (ma instanceof CustomAnnotation) {
CustomAnnotation customAnnotation = (CustomAnnotation) ma;
System.out.println("構造器 name: "
+ customAnnotation.name());
System.out.println("構造器 value: "
+ customAnnotation.value());
}
}
}
// 獲取類的公有方法
Method[] methods = c0.getMethods();
// Annotation annotation =
// methods[1].getAnnotation(CustomAnnotation.class);
for (Method method : methods) {
Annotation[] methodAnnotation = method.getAnnotations();
for (Annotation ma : methodAnnotation) {
if (ma instanceof CustomAnnotation) {
CustomAnnotation customAnnotation = (CustomAnnotation) ma;
System.out.println("method name: "
+ customAnnotation.name());
System.out.println("method value: "
+ customAnnotation.value());
}
}
// 獲取方法上的所有引數注解
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
for(Annotation[] pa : parameterAnnotations){
for(Annotation a:pa){
if(a instanceof CustomAnnotation){
System.out.println("method param name: "
+ ((CustomAnnotation) a).name());
System.out.println("method param value: "
+ ((CustomAnnotation) a).value());
}
}
}
}
}
}
執行效果:

?
看到了吧,一個類上可以多個注解,一個欄位也可以有多個注解,構造器上也可以多個注解,方法上也可以有多個注解、引數上也可以有多個注解,而類是可以有多個欄位、多個構造器(每個構造器都可能有多個引數)、多個方法(每個方法也都肯能有多個引數)),所以真正寫框架時光邏輯性if else判斷就折騰 了,,,舉個例子類上有A注解執行什么代碼,有B注解執行什么代碼,以此類推欄位、構造器、方法、引數的多個注解的處理程序,
實際開發中我們也會用到自定義注解,比如:
?
自定義注解是很強大的功能,廣泛應用于框架(Struts,hibernate,Mybatis,Spring, Spring boot,sping cloud,dubbo等)和系統開發公共模塊(比如上圖中的登錄攔截和取當前用戶)中
參考:
0. Java程式員必須掌握的5個注解! https://developer.51cto.com/art/201807/577539.htm
1. Lesson: Annotations
https://docs.oracle.com/javase/tutorial/java/annotations/
2. Java Annotations Tutorial https://www.javacodegeeks.com/2014/11/java-annotations-tutorial.html
3. How To Process Java Annotations
https://www.javacodegeeks.com/2015/01/how-to-process-java-annotations.html
4. An introductory guide to annotations and annotation processors
https://blog.frankel.ch/introductory-guide-annotation-processor/
5. Java Annotation Processing and Creating a Builder
https://www.baeldung.com/java-annotation-processing-builder
6. How and when to use Enums and Annotations https://www.javacodegeeks.com/2015/09/how-and-when-to-use-enums-and-annotations.html
7. Common Annotations for the Java? Platform? https://download.oracle.com/otn-pub/jcp/common_annotations-1_3-mrel3-eval-spec/jsr-250.pdf?AuthParam=1590270326_b56b01b1aeacddec8562720c1b2f27b8
8. Java - Understanding @Inherited meta annotation
https://www.logicbig.com/tutorials/core-java-tutorial/annotations/inherited-meta-annotation.html
9. 深入理解java注解的實作原理 https://mp.weixin.qq.com/s?__biz=MzAxMjY1NTIxNA==&mid=2454441897&idx=1&sn=729688d470c94560c1e73e79f0c13adc&chksm=8c11e0a8bb6669be1cc4daee95b221ba437d536d598520d635fac4f18612dded58d6fddb0dce&scene=21#wechat_redirect
10. Annotations in Java 5.0 https://javabeat.net/annotations-in-java-5-0/
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/182411.html
標籤:Java
