日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

后端JAVA:说说你对【注解】的理解

發布時間:2023/12/10 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 后端JAVA:说说你对【注解】的理解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文主要內容如下:

背景

現在已經處于注解盛行時代,注解@Override ,這個注解是再熟悉不過了,還有@Controller、@RequestMapping、@Service.....

注解已經是作為一個開發中必備的技能了。

如果在面試中被問到注解,說不出個123,就只能回去等通知了。

什么是注解?

注解annotation是JavaSE5.0中新增功能。可以理解為注解是一種標記,這種標記可以在編譯、類加載、運行時被讀取,并執行相應的處理。

它可以添加到程序的任何元素上:包聲明、類型聲明、構造方法、普通方法、成員變量、參數。

注解的老大:

????package?java.lang.annotation;//是個接口public?interface?Annotation?{????boolean?equals(Object?obj);int?hashCode();?String?toString();?//獲取注解類型Class<??extends?Annotation>?annotationType();}

JDK自帶為我們提供了元注解,下面就來聊聊JDK的元注解。

元注解有哪些?

JDK為我們提供五個元注解,位于java.lang.annotation 包目錄下。分別為:

  • @Retention

  • @Target

  • @Documented

  • @Inherited

  • @Repeatable

Retention注解

字面翻譯:

該注解就是定義該注解是作用于什么階段。

編譯、類加載、運行(使用最多)

注解源碼:

????@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.ANNOTATION_TYPE)public?@interface?Retention?{/***?Returns?the?retention?policy.*?@return?the?retention?policy*/RetentionPolicy?value();}

保留策略

????package?java.lang.annotation;public?enum?RetentionPolicy?{?SOURCE,?CLASS,?RUNTIME}

SOURCE:只在Java源代碼中,編譯器編譯的時候會把它直接丟棄。

CLASS:編譯器將注解記錄在.class文件中。當運行Java程序時,JVM不能獲取注解信息。這是默認值。

RUNTIME:編譯器將注解記錄在.class文件中。當運行Java程序時,JVM也能獲取注解信息。程序可以通過反射獲取注解信息。

注意:如果使用該注解的時候必須指定value的值。

Target注解

字面意義為目標,下面來看看器源碼:

????@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.ANNOTATION_TYPE)public?@interface?Target?{//元素類型ElementType[]?value();}public?enum?ElementType?{?TYPE,?FIELD,?METHOD,?PARAMETER,?CONSTRUCTOR,?LOCAL_VARIABLE,?ANNOTATION_TYPE,?PACKAGE,?/**?@since?1.8*/TYPE_PARAMETER,/**?@since?1.8*/TYPE_USE}

Target注解是在聲明創建一個注解的時候,指示該注解可以作用于程序中的哪些元素。

它里邊也包含一個名為value的成員變量,value成員變量的值有如下幾種

  • ANNOTATION_TYPE:指定當前注解只能修飾其它注解

  • CONSTRUCTOR:指定當前注解只能修飾構造方法

  • FIELD:指定當前注解只能修飾成員變量

  • LOCAL_VARIABLE:指定當前注解只能修飾局部變量

  • METHOD:指定當前注解只能修飾方法

  • PACKAGE:指定當前注解只能修飾包

  • PARAMETER:指定當前注解只能修飾參數

  • TYPE:指定當前注解可以修飾類,接口,其它注解,枚舉等類型

比如說:常用的Spring的注解@Controller,是用來作用于類上的。

Documented 注解

字面意義就是文檔。@Documented用于描述其它類型的annotation應該被作為被標注的程序成員的公共API,因此可以被例如javadoc此類的工具文? ? 檔化。Documented是一個標記注解,沒有成員 。

@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Documented { }

主要是用來生成文檔的,工作中基本上很少使用,作為了解就可以了。

Inherited 注解

字面意義:

@Inherited注解是在聲明創建一個注解的時候,指定該注解將具有繼承性。

Inherited 源碼:

????@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.ANNOTATION_TYPE)public?@interface?Inherited?{}

如果某個類使用了該注解@Xx,則其子類也將自動被此注解@Xx所修飾。

使用模板:

????@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Inheritedpublic?@interface?A?{}@Apublic?class?Base?{}//Sub也帶有@Apublic?class?Sub?extends?Base?{}
Repeatable注解

@Repeatable元注解,顧名思義,重復注解,就是在聲明創建注解的時候,指定該注解可以被同一個程序元素多次使用。這是JDK8新增的注解,重復注解只是一種簡單化寫法,這種簡單化寫法是一種假象。多個重復注解其實會被作為“容器”注解的value成員變量的數組元素。

比如下面Spring中注解ComponentScan:

????@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documented@Repeatable(ComponentScans.class)public?@interface?ComponentScan?{}@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documentedpublic?@interface?ComponentScans?{ComponentScan[]?value();}

使用案例

????import?org.springframework.context.annotation.Bean;import?org.springframework.context.annotation.ComponentScan;import?org.springframework.context.annotation.ComponentScans;@ComponentScans(value?=?{@ComponentScan(value?=?"com.tian.pakage0"),@ComponentScan(value?=?"com.tian.pakage1")})public?class?MainConfig?{@Beanpublic?User?person()?{return?new?User();}}

基本注解

注解必須使用工具來處理,工具負責提取注解中包含的元數據,工具還會根據這些元數據增加額外的功能。下面我們先來了解一下5個基本注解的用法。

  • Override

  • SafeVarargs

  • SuppressWarnings

  • FunctionalInterface

  • Deprecated

下面我們就來說說這五個注解。

Override

用于標識方法,標識該方法屬于重寫父類的方法 。

????//只能用于方法上@Target(ElementType.METHOD)//源碼中編譯時就會使用@Retention(RetentionPolicy.SOURCE)public?@interface?Override?{}

此注解表面是重寫父類的方法,只能用于方法上,并且用于編譯階段,我們在開發的時候,如果注解使用不當,在源碼編譯時立馬就會做出提示。

SafeVarargs

@SafeVarargs注解是在JDK7中引入的。此注解適用于接受varargs參數的final和static方法或構造函數。此注解用于確保方法不會對其varargs參數執行不安全的操作。從Java9開始,@SafeVarargs注解也適用于私有實例方法。

@SafeVarargs源碼

????@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.CONSTRUCTOR,?ElementType.METHOD})public?@interface?SafeVarargs?{}

使用案例

如果不使用此注解

public class SafevarargsTest {public static void main(String[] args) {// 傳遞可變參數,參數是泛型集合display(10, 20, 30);// 傳遞可變參數,參數是非泛型集合display("10", 20, 1000L); // 會有編譯警告}public static <T> void display(T... array) {for (T arg : array) {System.out.println(arg.getClass().getName() + ":" + arg);}} }

display方法會提示

如果我們給這個方法添加此注解后

上面的代碼在可變參數display前添加了@SafeVarargs注解,當然也可以使用 @SuppressWarnings("unchecked") 注解,可是,兩者相比較來說的話@SafeVarargs注解更適合。

注意:@SafeVarargs注解不適用于非static或非final聲明的方法,對于未聲明為static或final的方法,假如,要抑制unchecked警告,可以使用@SuppressWarnings注解。

SuppressWarnings

用于有選擇的關閉編譯器對類、方法、成員變量、變量初始化的警告。

????@Target({TYPE,?FIELD,?METHOD,?PARAMETER,?CONSTRUCTOR,?LOCAL_VARIABLE})@Retention(RetentionPolicy.SOURCE)public?@interface?SuppressWarnings?{String[]?value();}

編譯時期就會做出提示,使用范圍也是比較廣泛,可以適用于類、接口、枚舉、方法、字段等。

我們開發過程中見過最多的應該是集合存放數據的時候,比如下面的例子。

但是如果我們把第一行代碼注釋放開。

這樣就不會提示了。

FunctionalInterface

JDK8新增注解。@FunctionalInterface標記在接口上,“函數式接口”是指僅僅只包含一個抽象方法的接口。

源碼

????@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public?@interface?FunctionalInterface?{}

1、該注解只能標記在”有且僅有一個抽象方法”的接口上。

2、JDK8接口中的靜態方法和默認方法,都不算是抽象方法。

3、接口默認繼承java.lang.Object,所以如果接口顯示聲明覆蓋了Object中方法,那么也不算抽象方法。

4、該注解不是必須的,如果一個接口符合”函數式接口”定義,那么加不加該注解都沒有影響。加上該注解能夠更好地讓編譯器進行檢查。如果編寫的不是函數式接口,但是加上了@FunctionInterface,那么編譯器會報錯。

5、@FunctionalInterface 注解的interface。它的特點是其中只有一個子類必須要實現的abstract方法。

使用場景

Callable、Runnable等就有使用到。

????@FunctionalInterfacepublic?interface?Callable<V>?{V?call()?throws?Exception;}@FunctionalInterfacepublic?interface?Runnable?{public?abstract?void?run();}
Deprecated

用于標識方法或類,標識該類或方法已過時,建議不要使用 。

????@Documented@Retention(RetentionPolicy.RUNTIME)@Target(value={CONSTRUCTOR,?FIELD,?LOCAL_VARIABLE,?METHOD,?PACKAGE,?PARAMETER,?TYPE})public?@interface?Deprecated?{}

使用范圍就想到廣泛了,構造方法、字段、方法等。

注意:只是提示過時了,不建議使用,不代表不能用,但是我們如果想用某個使用此注解標記的方法或者類的時候,建議找找有沒有替換方案,實在沒有替換方案,搞清楚為什么它會被設置成過時,使用不當可能會對我們的程序造成你意想不到問題,也可能會挖坑。

自定義注解

終于來到自定義了,下面我們來自定義一個注解。

使用@interface自定義注解時,自動繼承了java.lang.annotation.Annotation接口,由編譯程序自動完成其他細節。在定義注解時,不能繼承其他的注解或接口。@interface用來聲明一個注解,其中的每一個方法實際上是聲明了一個配置參數。方法的名稱就是參數的名稱,返回值類型就是參數的類型(返回值類型只能是基本類型、Class、String、enum)。可以通過default來聲明參數的默認值。

格式
????public?@interface?注解名?{定義體}?
案例

自定義我們的注解

????@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public?@interface??MyInterface?{String?value()?default?"";}

使用階段為運行階段,目標是在方法上。定義一個屬性value默認值為空字符串。

下面我們就來使用我們定義的注解。

????import?java.lang.reflect.Method;public?class?InterfaceDemo?{//@MyInterface("老田自定義的注解")//@MyInterface@MyInterface(value?=?"老田自定義的注解")public?void?test()?{//?TODO:}public?static?void?main(String[]?args)?{InterfaceDemo?interfaceDemo?=?new?InterfaceDemo();Class<?>?clazz?=?interfaceDemo.getClass();Method[]?methods?=?clazz.getMethods();for?(Method?method?:?methods)?{if?("test".contentEquals(method.getName()))?{System.out.println("方法名稱=?"?+?method.getName());MyInterface?myInterface?=?method.getAnnotation(MyInterface.class);System.out.println("方法上的注解=?"?+?myInterface);System.out.println("枚舉值=?"?+?myInterface.value());}}}}

如果沒有指定value的值,那就使用默認值,value兩種方式賦值:

????@MyInterface("老田自定義的注解")@MyInterface(value?=?"老田自定義的注解")

然后我們運行上面的代碼,輸出結果為:

以上我們就搞定了自定義注解以及使用,獲取屬性值。

注解是普通類還是接口?

使用javap查看我們自定義的注解.class文件內容。

這里Annotation是接口:

????public?interface?Annotation?{}

那么證明,我們自定義的注解是extend接口Annotation,由此可知注解就是接口。

自定義注解注意點

解參數的可支持數據類型:

  • 所有基本數據類型(int,float,boolean,byte,double,char,long,short)

  • String類型

  • Class類型

  • enum類型

  • Annotation類型

  • 以上所有類型的數組

Annotation類型里面的參數該怎么設定:

  • 只能用public或默認(default)這兩個訪問權修飾.例如,String value();這里把方法設為defaul默認類型。

  • 參數成員只能用基本類型byte,short,char,int,long,float,double,boolean八種基本數據類型 和 String,Enum,Class,annotations等數據類型,以及這一些類型的數組.例如,String value();這里的參數成員就為String。

  • 如果只有一個參數成員,最好把參數名稱設為"value",后加小括號.例:下面的例子FruitName注解就只有一個參數成員。

如何獲取注解?

共有以下五種方式:

  • 獲取類上的注解:Class類的getAnnotation()

  • 獲取方法上的注解:Method類的getAnnotation()

  • 獲取字段上的注解:Field類的 getAnnotation()

  • 獲取構造方法上的注解:Constructor類的getAnnotation()

  • 獲取包上的注解:Package類的getAnnotation()

  • 如果此元素上存在指定的注釋類型,則此方法返回該元素的注釋,否則返回null。從上面的的集中方式中發現,都是使用getAnnotation()方法獲取的,相信大多數人都能猜到為什么都是同一個方法名稱。

    下面就來說說Java中注解獲取的鼻祖:

    java.lang.reflect.AnnotatedElement

    此接口所有方法

    看看AnnotatedElement類圖:

    發現前面說的獲取注解的類,全部都實現了AnnotatedElement接口。

    所以程序通過反射獲取了某個類的AnnotatedElement對象之后,程序就可以調用該對象的方法。

    如下四個個方法來訪問Annotation信息:

    「getAnnotation」

    返回該程序元素上存在的、指定類型的注解,如果該類型注解不存在,則返回null。

    「getAnnotations」

    返回該程序元素上存在的所有注解。

    「isAnnotationPresent」

    判斷該程序元素上是否包指定類型的注解,存在則返回true,否則返回false。

    「getDeclaredAnnotations」

    返回直接存在于此元素上的所有注釋。與此接口中的其他方法不同,該方法將忽略繼承的注釋。(如果沒有注釋直接存在于此元素上,則返回長度為零的一個數組。)該方法的調用者可以隨意修改返回的數組;這不會對其他調用者返回的數組產生任何影響

    總結

    為什么要學習注解?元注解有哪些?基本注解有哪些?如何自定義注解?注解是普通類還是接口?自定義注解需要注意些什么?獲取獲取注解?

    參考:

    qqe2.com/java/post/1853.html cnblogs.com/peida/archive/2013/04/24/3036689.html

    IT技術分享社區

    個人博客網站:https://programmerblog.xyz

    文章推薦程序員效率:畫流程圖常用的工具程序員效率:整理常用的在線筆記軟件遠程辦公:常用的遠程協助軟件,你都知道嗎?51單片機程序下載、ISP及串口基礎知識硬件:斷路器、接觸器、繼電器基礎知識

    創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

    總結

    以上是生活随笔為你收集整理的后端JAVA:说说你对【注解】的理解的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。