Java 註解

元信息html

Java 註解(Annotation)又稱 Java 標註,是 JDK5.0 引入的一種註釋機制。java

Java 語言中的類、方法、變量、參數和包等均可以被標註。和 Javadoc 不一樣,Java 標註能夠經過反射獲取標註內容。在編譯器生成類文件時,標註能夠被嵌入到字節碼中。Java 虛擬機能夠保留標註內容,在運行時能夠獲取到標註內容 。 固然它也支持自定義 Java 標註。程序員

因爲jdk和框架大量使用註解,我也簡單介紹下註解爲什麼物,若您發現文章中存在錯誤或不足的地方,但願您能指出!spring

Java 定義了一套註解,共有 7 個,3 個在 java.lang 中,剩下 4 個在 java.lang.annotation 中。架構

做用在代碼的註解是oracle

  • @Override - 檢查該方法是不是重寫方法。若是發現其父類,或者是引用的接口中並無該方法時,會報編譯錯誤。
  • @Deprecated - 標記過期方法。若是使用該方法,會報編譯警告。
  • @SuppressWarnings - 指示編譯器去忽略註解中聲明的警告。

做用在其餘註解的註解(或者說 元註解)是:框架

  • @Retention - 標識這個註解怎麼保存,是隻在代碼中,仍是編入class文件中,或者是在運行時能夠經過反射訪問。
  • @Documented - 標記這些註解是否包含在用戶文檔中。
  • @Target - 標記這個註解應該是哪一種 Java 成員。
  • @Inherited - 標記這個註解是繼承於哪一個註解類(默認 註解並無繼承於任何子類)

從 Java 7 開始,額外添加了 3 個註解:ide

  • @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 = " 類上的註解")
public class SampleClass {
	@CustomAnnotation(name = "field Annotation", value = "字段上的註解")
	public String sampleField;

	@CustomAnnotation(name = "constructor Annotation", value = "構造器上的註解")
	public SampleClass(String sampleField) {
		super();
		this.sampleField = sampleField;
	}

	@CustomAnnotation(name = "Method Annotation getSampleField", value = "getSampleField無參方法上的註解")
	public String getSampleField() {
		System.out.println("getSampleField");
		return sampleField;
	}

	@CustomAnnotation(name = "Method Annotation setSampleField", value = "setSampleField方法上的註解")
	public void setSampleField(String sampleField) {
		System.out.println("setSampleField=" + sampleField);
		this.sampleField = sampleField;
	}

	@CustomAnnotation(name = "Method Annotation getSampleField hava param", value = "getSampleField有參方法上的註解")
	private String getSampleField(String sampleField) {
		return sampleField;
	}
}

測試類

/** * * @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

相關文章
相關標籤/搜索