java註解核心知識總結

1. 前言

前幾年咱們的項目還在structs 2 上跑,有一次問一個同事是否知道 Spring Boot,同事說那不是用註解來開發的嗎。雖然這個答案並不徹底對,可是從客觀上Spring Boot對剛剛接觸它的人來講最醒目的就是註解了。那麼今天咱們來了解一下Java語言的核心功能——註解。html

2.註解是什麼

public @interface Anno {
}

複製代碼

以上就是一個最簡單的註解聲明。它能夠註釋到類、接口、方法以及變量上。經過向方法,接口,類或字段添加註釋,爲其綁定的源代碼分配額外的元數據。java

3.註解的用途

經過註解咱們能夠通知編譯器有關警告和錯誤的信息在編譯時操做源代碼在運行時修改或檢查行爲。jdk提供內置5個基本註解來處理代碼檢查。數組

  • @Override 來標記該方法重寫或替換繼承的方法的行爲。若是你重寫了父類方法不帶該註解會觸發一些警告。
  • @SuppressWarnings 表示咱們要忽略部分代碼中的某些警告。如忽略潛在的類型不安全轉換警告unchecked。
  • @Deprecated 用來表示類、方法已通過時,不推薦使用。若是你強行使用編譯器會在編譯時進行警告。
  • @Safevarargs 抑制「堆污染」警告。「堆污染」指的是將一個不帶泛型的對象賦給帶泛型的變量時引起的的類型問題。若是你不想看到該警告就可使用該註解來抑制。
  • @FunctionalInterface java 8 新增註解,只能做用於接口上來標識該接口是函數式接口。java中函數式接口表示該接口只能有一個抽象方法。若是一個接口被此註解修飾,若是添加第二個抽象方法將沒法經過編譯。

註解能夠將一些元數據傳遞給你編寫的邏輯。好比Spring Mvc 中的一個經常使用註解@RequestMapping,咱們能夠經過value參數來傳遞一個path路徑,Spring Mvc經過對請求的路徑的匹配來做出是否路由到該path上。 目前大量的的框架都依賴註解,好比Spring、hibernate、dubbo等等。安全

4.元註解

元註解是能夠應用於其餘註解的註解。來加強或者配置目標註解的機制。jdk目前提供了5個元註解。若是你須要開發自定義註解,請務必熟悉它們:bash

  • @Retention 只能用於修飾註解,來指定被修飾註解能夠保留多長時間。規定了三種策略:app

    • RetentionPolicy.SOURCE 這種策略下被修飾的註解只能存在於源代碼中,編譯後被丟棄,經過反射沒法獲取到被修飾的註解。
    • RetentionPolicy.CLASS 這種策略下被修飾的註解會被編譯進字節碼文件中。可是JVM沒法獲取到被修飾的註解。這是一個默認值,當你聲明的註解沒有添加任何保留策略時,會默認指定該策略。
    • RetentionPolicy.RUNTIME 這種策略下被修飾的註解不但能夠編譯進字節碼文件。並且JVM也能夠獲取被該註解修飾的註解。並且程序編碼也能夠經過反射來獲取被該註解修飾的註解的一些元信息。
  • @Target 用於指定被修飾註解的修飾目標類型。若是一個註解明確了可修飾的目標類型,則只能修飾指定的類型。由枚舉ElementType來規定。框架

  • TYPE 只能修飾 類、接口、枚舉。ide

  • FIELD 只能修飾成員變量,包含枚舉內的常量。函數

  • METHOD 只能修飾方法。工具

  • PARAMETER 只能修飾參數。

  • CONSTRUCTOR 只能修飾構造器。

  • LOCAL_VARIABLE 只能修飾局部變量。

  • ANNOTATION_TYPE 只能修飾註解。

  • PACKAGE 只能修飾包定義。也就是package-info.java中

  • TYPE_PARAMETER java 8 新增 表示該註解能寫在類型參數的聲明語句中。 類型參數聲明如: 、

  • TYPE_USE java 8 新增 註解能夠再任何用到類型的地方使用。

  • @Documented 被該註解修飾的註解能夠被javadoc工具提取爲文檔。

  • @Inherited 被該註解修飾的註解有繼承性。這裏要注意一些要點首先這種繼承性體現的類之間而不是接口之間,並且註解必須是對JVM可見。也就是@Retention爲RetentionPolicy.RUNTIME 才起做用。

  • @Repeatable java 8 新增。在此以前在同一個元素上同一個註解只能出現一次。@Repeatable可讓一個註解屢次出如今一個元素上。

5.自定義註解

自定義註解跟自定義接口相似,可是還有一些區別,實際開發你須要對自定義註解進行元註解註釋。註解中的成員變量以無參抽象方法來聲明,成員變量並非全部類型都支持,目前只支持如下類型:

  • 全部基本類型(int,float,boolean,byte,double,char,long,short)

  • String

  • Class (如:Class<?> 或 Class)

  • enum java枚舉

  • Annotation

    下面咱們就來自定義一個註解:

/**
 * 聲明一個能夠標記在類、接口、枚舉、方法上的註解。
 * 而且JVM Runtime 可見、可生成文檔
 *
 * @author Dax
 * @since 17 :27  2019/9/4
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Anno {
    /**
     * 若方法名爲value且註解聲明只須要聲明value屬性時,
     * value能夠省略, @Anno("anno") 等同於 @Anno(value="anno")
     *
     * @return the string
     */
    String value();

    /**
     * 一個具備默認值的 String 類型屬性。
     * name若不顯式聲明,則默認值爲"" 。  
     * 聲明默認值經過 default + 默認值 來聲明
     *
     * @return the string
     */
    String name() default "";

    /**
     * 一個Class 類型屬性,沒有默認值。其餘支持類型再也不舉例
     *
     * @return the class
     */
    Class<?> clazz();
}
複製代碼

如何獲取註解中的元數據

全部的註解都是java.lang.annotation.Annotation 的子類。只有RetentionPolicy爲RUNTIME的 註解才能經過反射獲取。在反射包中提供了AnnotatedElement 接口來對元素上的可捕捉到的註解進行處理。該接口是Class、Method、Constructor等程序元素對象的父接口。也就是說只要能獲取程序元素對象就能對其存在的註解進行處理。主要方法有:

  • boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 判斷是否存在 annotationClass類型的註解。
  • T getAnnotation(Class annotationClass) 若是在當前元素上存在參數所指定類型(annotationClass)的註解,則返回對應的註解,不然將返回null。
  • Annotation[] getAnnotations() 返回在這個元素上的全部註解。若是該元素沒有註解,則返回值是長度爲0的數組。該方法的調用者能夠自由地修改返回的數組;它不會對返回給其餘調用者的數組產生影響。
  • T[] getAnnotationsByType(Class annotationClass) 返回與該元素相關聯的註解。若是沒有與此元素相關聯的註解,則返回值是長度爲0的數組。這個方法與getAnnotation(Class)的區別在於,該方法檢測其參數是否爲可重複的註解類型(JLS 9.6),若是是,則嘗試經過「looking through」容器註解來查找該類型的一個或多個註解。該方法的調用者能夠自由地修改返回的數組;它不會對返回給其餘調用者的數組產生影響。參考@Repeatable。
  • T getDeclaredAnnotation(Class annotationClass) 若是參數中所指定類型的註解是直接存在於當前元素上的,則返回對應的註解,不然將返回null。這個方法忽略了繼承的註解。(若是沒有直接在此元素上顯示註釋,則返回null。)
  • T[] getDeclaredAnnotationsByType(Class annotationClass) 可獲取重複註解可是忽略掉繼承註解。
  • Annotation[] getDeclaredAnnotations() 跟上面的註解區別在於不能獲取重複註解。

基本上對這個接口的方法進行學習後就能夠知道如何獲取註解的元數據了。下面咱們寫一個例子,仍是上面的Anno註解爲例:

/**
 * 被註解標記的類
 **/
@Anno("hello")
public class Foo {}

/**
 * 經過獲取Foo 的Class 類,
 * 而後就能夠根據上面已經介紹的方法來獲取value的值了
 * @author dax
 * @since 2019/9/4 22:17
 */
public class Main {
    public static void main(String[] args) {
        Anno annotation = Foo.class.getAnnotation(Anno.class);

        String value = annotation.value();
        System.out.println("value = " + value);
    }
}

複製代碼

總結

今天咱們系統地對註解進行了概括,相信你已經對註解有了系統性的認識。其實註解還能夠幹一些花式操做,好比lombok框架。後面咱們會介紹相關的註解技術,多多關注。

原創做者:碼農小胖哥 轉載地址:gper.club/articles/7e…

相關文章
相關標籤/搜索