JAVA-註解

註解定義

Java 註解是附加在代碼中的一些元信息,用於一些工具在編譯、運行時進行解析和使用,起到說明、配置的功能。註解不會也不能影響代碼的實際邏輯,僅僅起到輔助性的作用。註解包含在 java.lang.annotation 包中。
注意:註解本身不是代碼的一部分,註解作用在類或者方法、屬性上不會自己起作用,需要其他工具(代碼)主動去獲取註解的信息。

作用

  • 替代配置文件:例如spring中的中@Autowired,@Service
  • 編譯時進行格式檢查:例如Override

jdk註解

  • @Override,表示當前的方法定義將覆蓋超類中的方法。
  • @Deprecated,使用了註解爲它的元素編譯器將發出警告,因爲註解
  • @Deprecated是不贊成使用的代碼,被棄用的代碼。
  • @SuppressWarnings,關閉不當編輯器警告信息。
  • @Functionallnterface:java8 函數式接口註解,一般有這個註解的方法可以直接使用 lambda 表達式

元註解(定義註解的註解)

元註解是可以註解到註解上的註解,或者說元註解是一種基本註解,但是它能夠應用到其它的註解上面。基本的元標籤有:

  • @Retention:定義了該註解的生命週期
  • @Documented:簡單的標記註解,表示是否將註解信息添加在 Java 文檔
  • @Target:表示該註解用於什麼地方
  • @Inherited:定義了一個註釋與子類的關係。如果一個超類帶有 @Inherited 註解,那麼對於該超類,它的子類如果沒有被任何註解應用的話,那麼這個子類就繼承了超類的註解。
    @Repeatable:@Repeatable 是 Java 8 中加入的,是指可重複的意思。通常使用 @Repeatable 的時候指註解的值可以同時取多個。

如何定義一個註解

註解的屬性也叫做成員變量。註解只有成員變量,沒有方法。註解的成員變量在註解的定義中以無形參的方法形式來聲明,其方法名定義了該成員變量的名字,其返回值定義了該成員變量的類型
注意:註解可以有默認值,需要用 default 關鍵字指定。如果註解內只有一個名爲 value 的屬性時,應用該屬性時可以將值直接寫到括號內,不用寫 value = “…”

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Person {
    int id() default 100;
    String name();
    String language();
    String company();
}

上面假設定義了一個名爲 @Person 的註解,該註解有 id, name, language, company 三個屬性。使用的時候,我們應該對其賦值。賦值的方式類似於 key=“value” 的方式進行,屬性之間用 “,” 隔開:

@Coder(id = 10086, name = "GRQ", language = "JAVA", company = "cetc")
public class personTest() {
}

自定義註解步驟

自定義註解類編寫的規則:

  • 註解類型定義爲 @interface,所有的註解會自動繼承 java.lang.Annotation
  • 這一接口,而且不能再去繼承其他的類或接口;
  • 參數成員只能用 public 或 default 兩個關鍵字修飾;
  • 參數成員只能用基本類型:byte, short, char, int, long, float, double, boolean,以及String, Enum, Class, Annotations 等數據類型,以及這些類型的數組;
  • 要獲取類方法和字段的註解信息,必須通過Java 的反射技術;
  • 註解也可以不定義成員變量,這種註解具有標記作用;
  • 自定義註解需要使用元註解進行編寫;
    大家可以參考這篇文章

註解底層原理

從java源碼到class字節碼是由編譯器完成的,編譯器會對java源碼進行解析並生成class文件,而註解也是在編譯時由編譯器進行處理,編譯器會對註解符號處理並附加到class結構中,根據jvm規範,class文件結構是嚴格有序的格式,唯一可以附加信息到class結構中的方式就是保存到class結構的attributes屬性中。 我們知道對於類、字段、方法,在class結構中都有自己特定的表結構,而且各自都有自己的屬性,而對於註解,作用的範圍也可以不同,可以作用在類上,也可以作用在字段或方法上,這時編譯器會對應將註解信息存放到類、字段、方法自己的屬性上。

在我們的AnnotationTest.java類被編譯後,在對應的AnnotationTest.class文件中會包含一個RuntimeVisibleAnnotations屬性,由於這個註解是作用在類上,所以此屬性被添加到類的屬性集上。即Test註解的鍵值對value=test會被記錄起來。而當JVM加載AnnotationTest.class文件字節碼時,就會將RuntimeVisibleAnnotations屬性值保存到AnnotationTest的Class對象中,於是就可以通過AnnotationTest.class.getAnnotation(Test.class)獲取到Test註解對象,進而再通過Test註解對象獲取到Test裏面的屬性值。

這裏可能會有疑問,Test註解對象是什麼?其實註解被編譯後的本質就是一個繼承Annotation接口的接口,所以@Test其實就是“public interface Test extends Annotation”,當我們通過AnnotationTest.class.getAnnotation(Test.class)調用時,JDK會通過動態代理生成一個實現了Test接口的對象,並把將RuntimeVisibleAnnotations屬性值設置進此對象中,此對象即爲Test註解對象,通過它的value()方法就可以獲取到註解值。

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