JAVA核心知識點--元註解詳解

目錄

Annotation(註解)

meta-annotation(元註解)

@Target註解

@Retention註解

@Documented註解

@Inherited註解

註解應用舉例

Annotation(註解)
從JDK 1.5開始, Java增加了對元數據(MetaData)的支持,也就是 Annotation(註解)。

註解其實就是代碼裏的特殊標記,它用於替代配置文件:傳統方式通過配置文件告訴類如何運行,有了註解技術後,開發人員可以通過註解告訴類如何運行。在Java技術裏註解的典型應用是:可以通過反射技術去得到類裏面的註解,以決定怎麼去運行類。

註解可以標記在包、類、屬性、方法,方法參數以及局部變量上,且同一個地方可以同時標記多個註解。

// 抑制編譯期的未指定泛型、未使用和過時警告
@SuppressWarnings({ “rawtypes”, “unused”, “deprecation” })
// 重寫
@Override
meta-annotation(元註解)
除了直接使用JDK 定義好的註解,我們還可以自定義註解,在JDK 1.5中提供了4個標準的用來對註解類型進行註解的註解類,我們稱之爲 meta-annotation(元註解),他們分別是:

@Target

@Retention

@Documented

@Inherited

我們可以使用這4個元註解來對我們自定義的註解類型進行註解,接下來,我們挨個對這4個元註解的作用進行介紹。

@Target註解
 Target註解的作用是:描述註解的使用範圍(即:被修飾的註解可以用在什麼地方) 。

Target註解用來說明那些被它所註解的註解類可修飾的對象範圍:註解可以用於修飾 packages、types(類、接口、枚舉、註解類)、類成員(方法、構造方法、成員變量、枚舉值)、方法參數和本地變量(如循環變量、catch參數),在定義註解類時使用了@Target 能夠更加清晰的知道它能夠被用來修飾哪些對象,它的取值範圍定義在ElementType 枚舉中。

public enum ElementType {

TYPE, // 類、接口、枚舉類

FIELD, // 成員變量(包括:枚舉常量)

METHOD, // 成員方法

PARAMETER, // 方法參數

CONSTRUCTOR, // 構造方法

LOCAL_VARIABLE, // 局部變量

ANNOTATION_TYPE, // 註解類

PACKAGE, // 可用於修飾:包

TYPE_PARAMETER, // 類型參數,JDK 1.8 新增

TYPE_USE // 使用類型的任何地方,JDK 1.8 新增

}
@Retention註解
Reteniton註解的作用是:描述註解保留的時間範圍(即:被描述的註解在它所修飾的類中可以被保留到何時) 。

Reteniton註解用來限定那些被它所註解的註解類在註解到其他類上以後,可被保留到何時,一共有三種策略,定義在RetentionPolicy枚舉中。

public enum RetentionPolicy {

SOURCE,    // 源文件保留
CLASS,       // 編譯期保留,默認值
RUNTIME   // 運行期保留,可通過反射去獲取註解信息

}
爲了驗證應用了這三種策略的註解類有何區別,分別使用三種策略各定義一個註解類做測試。

@Retention(RetentionPolicy.SOURCE)
public @interface SourcePolicy {

}
@Retention(RetentionPolicy.CLASS)
public @interface ClassPolicy {

}
@Retention(RetentionPolicy.RUNTIME)
public @interface RuntimePolicy {

}
用定義好的三個註解類分別去註解一個方法。

public class RetentionTest {

@SourcePolicy
public void sourcePolicy() {
}

@ClassPolicy
public void classPolicy() {
}

@RuntimePolicy
public void runtimePolicy() {
}

}

如圖所示,通過執行 javap -verbose RetentionTest命令獲取到的RetentionTest 的 class 字節碼內容如下。

{
public retention.RetentionTest();
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object.""😦)V
4: return
LineNumberTable:
line 3: 0

public void sourcePolicy();
flags: ACC_PUBLIC
Code:
stack=0, locals=1, args_size=1
0: return
LineNumberTable:
line 7: 0

public void classPolicy();
flags: ACC_PUBLIC
Code:
stack=0, locals=1, args_size=1
0: return
LineNumberTable:
line 11: 0
RuntimeInvisibleAnnotations:
0: #11()

public void runtimePolicy();
flags: ACC_PUBLIC
Code:
stack=0, locals=1, args_size=1
0: return
LineNumberTable:
line 15: 0
RuntimeVisibleAnnotations:
0: #14()
}
從 RetentionTest 的字節碼內容我們可以得出以下兩點結論:
           1. 編譯器並沒有記錄下 sourcePolicy() 方法的註解信息; 
           2. 編譯器分別使用了 RuntimeInvisibleAnnotations 和 RuntimeVisibleAnnotations 屬性去記錄了classPolicy()方法 和 runtimePolicy()方法 的註解信息;

@Documented註解
Documented註解的作用是:描述在使用 javadoc 工具爲類生成幫助文檔時是否要保留其註解信息。

爲了驗證Documented註解的作用到底是什麼,我們創建一個帶有 @Documented 的自定義註解類。

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Documented
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface MyDocumentedtAnnotation {

public String value() default "這是@Documented註解爲文檔添加的註釋";

}
再創建一個 MyDocumentedTest 類。

@MyDocumentedtAnnotation
public class MyDocumentedTest {

@Override
@MyDocumentedtAnnotation
public String toString() {
	return this.toString();
}

}
接下來,使用以下命令爲 MyDocumentedTest 類生成幫助文檔。

命令執行完成之後,會在當前目錄下生成一個 doc 文件夾,其內包含以下文件。

查看 index.html 幫助文檔,可以發現在類和方法上都保留了 MyDocumentedtAnnotation 註解信息。

修改 MyDocumentedtAnnotation 註解類,去掉上面的 @Documented 註解。

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Target({ElementType.TYPE,ElementType.METHOD})
public @interface MyDocumentedtAnnotation {

public String value() default "這是@Documented註解爲文檔添加的註釋";

}
重新生成幫助文檔,此時類和方法上的 MyDocumentedtAnnotation 註解信息都不見了。

@Inherited註解
Inherited註解的作用是:使被它修飾的註解具有繼承性(如果某個類使用了被@Inherited修飾的註解,則其子類將自動具有該註解)。

接下來我們使用代碼來進行測試,首先創建一個被@Inherited修飾的註解類MyInheritedAnnotation。

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyInheritedAnnotation {

public String name() default "pengjunlee";

}
創建一個帶有 MyInheritedAnnotation 註解的父類和一個無任何註解的子類。

@MyInheritedAnnotation(name=“parent”)
public class Parent {

}
public class Child extends Parent{

public static void main(String[] args) {
	Class<Child> child=Child.class;
	MyInheritedAnnotation annotation = child.getAnnotation(MyInheritedAnnotation.class);
	System.out.println(annotation.name());
}

}
運行程序,打印結果如下:

parent
註解應用舉例
首先自定義一個註解類。

package com.pengjunlee;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyAnnotation {

public String name() default "pengjunlee";

}
在 AnnotationTest 中使用反射獲取註解信息。

package com.pengjunlee;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

@MyAnnotation(name = “name of type”)
public class AnnotationTest {

@MyAnnotation(name = "name of method")
public String hello() {
	return "hello";
}

public static void main(String[] args) throws NoSuchMethodException, SecurityException {

	Class<AnnotationTest> annotationTest = AnnotationTest.class;
	// 獲取類上的所有註解
	Annotation[] annotations = annotationTest.getAnnotations();
	for (Annotation annotation : annotations) {
		// 獲取註解的全類名
		System.out.println(annotation.annotationType().getName());
	}

	// 獲取 hello() 方法
	Method method = annotationTest.getMethod("hello", new Class[] {});

	// hello() 方法上是否有 MyAnnotation 註解
	if (method.isAnnotationPresent(MyAnnotation.class)) {

		// 獲得註解
		MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);

		// 獲取註解的內容
		System.out.println(annotation.name());

	}
}

}
運行程序,打印結果如下:

com.pengjunlee.MyAnnotation
name of method
  
————————————————
版權聲明:本文爲CSDN博主「pengjunlee」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/pengjunlee/article/details/79683621

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章