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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

啊啊,终于搞明白了,原来注解是这么一回事。6000+字理解注解【一】

發(fā)布時(shí)間:2024/3/12 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 啊啊,终于搞明白了,原来注解是这么一回事。6000+字理解注解【一】 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

    • 前言
    • 復(fù)習(xí)注解
      • 元注解
        • @Retention 存活時(shí)間
        • @Documented 文檔
        • @Target 目標(biāo)
        • @Inherited 繼承
        • @Repeatable 可重復(fù)
      • 注解屬性
    • 注解實(shí)現(xiàn)-反射
      • 反射獲取注解方法
      • 注解的使用場(chǎng)景
      • 后續(xù)
      • 導(dǎo)航

前言

這兩天在gitHub上看一個(gè)開源項(xiàng)目,發(fā)現(xiàn)項(xiàng)目中有許多自定義注解。雖然在學(xué)JavaSE的時(shí)候?qū)W個(gè)注解,但是主要講的是如何自定義注解,和一些元注解的知識(shí)點(diǎn)。并沒有涉及到注解如何實(shí)現(xiàn)具體的功能。直到看到這個(gè)項(xiàng)目,突然醍醐灌頂。
由于篇幅過長(zhǎng),分成兩篇來(lái)寫。

復(fù)習(xí)注解

注解是在Java 1.5 的時(shí)候被引入的,注解的創(chuàng)建與接口十分相似。就是在interface關(guān)鍵字前面加一個(gè)@符號(hào)。

public @interface MyAnnotation{ }

創(chuàng)建玩注解之后就可以在想要添加主機(jī)的地方使用了,但是想要讓注解能夠正常工作,還需要給它化化妝。什么是化妝那,這里就要引入元注解的一個(gè)概念了,元注解他也是一個(gè)注解,只不過它是用來(lái)修飾注解的注解。有點(diǎn)迷?不慌咱慢慢看。

元注解

元注解一共有五種分別為:

  • @Retention
  • @Documented
  • @Target
  • @Inherited
  • @Repeatable
    他們的使用方法就是在創(chuàng)建注解的時(shí)候在,所要?jiǎng)?chuàng)建的注解上使用他們:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) ... ... public @interface MyAnnotation{ }

@Retention 存活時(shí)間

Retention中文意思是保留的意思。當(dāng)@Retention應(yīng)用到一個(gè)注解上的時(shí)候 ,通過參數(shù)可以設(shè)置這個(gè)注解的存活時(shí)間。什么是存活時(shí)間,就是說通過不同參數(shù)可以確定@Retention修飾的注解在那種情況下會(huì)消失,是保留到源碼階段、還是編譯階段、還是加載到JVM那。

下面看一下它的參數(shù):

  • RetentionPolicy.SOURCE

注解只被保留到編譯階段,當(dāng)編譯器編譯到它的時(shí)候看到參數(shù)為 RetentionPolicy.SOURCE會(huì)直接將其從源碼中剔除。

  • RetentionPolicy.SOURCE

注解制備保留到編譯進(jìn)行的時(shí)候,也就是能保證在編譯期間注解也存在,但是不能進(jìn)入JVM中。

  • RetentionPolicy.SOURCE

注解可以保留到程序中,它會(huì)被加載到JVM中從而在服務(wù)中起作用。

@Documented 文檔

這個(gè)注解,翻譯過來(lái)就是文檔。那他并沒有其他功能上的作用,主要作用就是能講注解中的元素包含到Javadoc中去。

@Target 目標(biāo)

Target 有目標(biāo)的意思,他的意思就是說,這個(gè)注解能夠使用的地方是哪里,是方法上、類上還是參數(shù)上。我們通過它的參數(shù)就可以進(jìn)行設(shè)置。

參數(shù)作用
ElementType.ANNOTATION_TYPE可以使用在注解上
ElementType.CONSTRUCTOR可以在構(gòu)造方法上使用
ElementType.FIELD可以在屬性上使用注解
ElementType.LOCAL_VARIABLE作用在局部變量上
ElementType.METHOD作用在方法上
ElementType.PACKAGE作用在包上
ElementType.PARAMETER作用在方法內(nèi)的參數(shù)上
ElementType.TYPE可以給類型進(jìn)行注解,比如類、接口、枚舉

@Inherited 繼承

Inherited 意思為繼承,這個(gè)元注解的作用有點(diǎn)繞。就是說如果@Inherited注解作用與自定義注解@MyAnnotation上,然后在A類上使用了自定義注解,然后A類的子類,就相當(dāng)于也擁有@MyAnnotation注解。

/*自定義注解*/ @Inherited public @interface MyAnnotation{ } --------------------------- /*A類*/ @MyAnnotation public class A{ }/*B類繼承A類*/ public class B extent A{ }/* //此時(shí),B類也繼承了A類的注解。相當(dāng)于 @MyAnnotation public class B extent A{ } */

@Repeatable 可重復(fù)

這個(gè)注解是在Java 1.8的時(shí)候加進(jìn)來(lái)的。那可重復(fù)是什么意思那,就是說使用注解的時(shí)候可以同時(shí)使用多次注解。

public class A{ @MyAnnotation("教師") @MyAnnotation("公務(wù)員")public void test(){}}

如果想實(shí)現(xiàn)這樣的效果,那么就需要使用@Repeatable注解修飾@MyAnnotation注解。@MyAnnotation才可以在一個(gè)方法或其它地方使用多次。

注解屬性

注解的屬性其實(shí)就好像實(shí)體類里面的屬性,只是寫法上有稍微的不同。但是注解是沒有方法的,

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) ... ... public @interface MyAnnotation{ int id(); String value(); }

注意這里id()和value()表示的不是方法而是屬性也可叫做注解的變量。
注解的賦值方法就是在使用注解的時(shí)候,通過注解中的對(duì)應(yīng)屬性="xxx"的形式

@MyAnnotation(id=101,value="Hello Annotation") public void test(){ }

注解屬性可以設(shè)置默認(rèn)值,也就是如果使用注解時(shí)沒有賦予特定的值,就使用默認(rèn)值。

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) ... ... public @interface MyAnnotation{ int id() default 101; String value(); }

這里還有一個(gè)注意點(diǎn),如果注解中只有一個(gè)名字為value的屬性的時(shí)候,應(yīng)用這個(gè)注解的時(shí)候可以直接填寫屬性值。

pulic @interface MyAnnotation{String value; } @MyAnnotation("Hi") public void test(){ }

如果定義的這個(gè)注解中沒有屬性值,我們?cè)谑褂米⒔獾臅r(shí)候就不用在寫括號(hào)了

@MyAnnotation public void test(){ }

注解實(shí)現(xiàn)-反射

注解的知識(shí)經(jīng)過上面的內(nèi)容,應(yīng)該能夠有個(gè)了解。那么我們定義好后注解,也是用了,但是并沒有什么實(shí)質(zhì)的效果。哪有人該說了那定義有什么用?其實(shí)不然,如果真的沒有用那么Java官方就不會(huì)定義注解了。

好下面我們就給自定義的注解注入靈魂,實(shí)現(xiàn)當(dāng)使用注解后完成相應(yīng)的功能。那該如何實(shí)現(xiàn)那,注解中又不能寫方法,之有屬性值, 我們也不能通過new獲取注解。這里就要提到一個(gè)比較重要的知識(shí)點(diǎn)就是反射

我們可以通過反射獲取作用在類或者方法上的注解讓,后進(jìn)行對(duì)應(yīng)的處理。

反射獲取注解方法

注解通過反射獲取。首先通過class對(duì)象的isAnnotationPresent()方法判斷他是否應(yīng)用了某注解。

public Boolean isAnnotationPresent(Class<? extent Annotation> annotationClass) {}

然后通過getAnnotation()方法來(lái)獲取Annotation對(duì)象。

public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}

或者是getAnnotations()方法

public Annotation[] getAnnotations(){}

前一種方法返回指定類型的注解,后一種方法返回注解到這個(gè)元素上的所有注解。
如果獲取到的Annotation如果不為null,則就可以調(diào)用他們的屬性方法了。比如

@MyAnnotation() public class Test{public static void main(String[] agrs){boolean hasAnnotation = Test.class.isAnnotationPressent(TestAnnotation.class);if(hasAnnotation){TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);System.out.println('id:'+testAnnotation.id());}} }

運(yùn)行結(jié)果:

id:101

上面是獲取類上的注解,其實(shí)方法、屬性的注解都是可以通過反射進(jìn)行獲取的。
自定注解:

package com.zhao.annotationaop.annotation;import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MyAnnotation {String value() default "Hello Annotation"; }

編寫測(cè)試類

public class TestAnnotation {@MyAnnotation("Hi")public void testMethod(){System.out.println("fun");}public static void main(String[] args) throws NoSuchMethodException {Class<TestAnnotation> aClass = TestAnnotation.class;Method msg = aClass.getDeclaredMethod("testMethod");msg.setAccessible(true);MyAnnotation annotation = msg.getAnnotation(MyAnnotation.class);System.out.println(annotation.value());} }

運(yùn)行結(jié)果

Hi

這里需要注意一下,如果想要注解在運(yùn)行時(shí)能夠獲取到,那么必須加上@Retention(RetentionPolicy.RUNTIME)這個(gè)注解參數(shù),因?yàn)檫@個(gè)參數(shù)是指,注解能在jvm中被執(zhí)行。

注解的使用場(chǎng)景

到這里應(yīng)該大家對(duì)注解都有一定的了解了,但是還是可能會(huì)有疑惑注解到底有什么用吶。
我們不妨先看看官方的回答:

注解是一系列元數(shù)據(jù),它提供數(shù)據(jù)用來(lái)解釋程序代碼,但是注解并非是所解釋的代碼本身的一部分。注解對(duì)于代碼的運(yùn)行效果沒有直接影響。
注解有許多用處,主要如下:

  • 提供信息給編譯器: 編譯器可以利用注解來(lái)探測(cè)錯(cuò)誤和警告信息
  • 編譯階段時(shí)的處理: 軟件工具可以用來(lái)利用注解信息來(lái)生成代碼、Html文檔或者做其它相應(yīng)處理。
  • 運(yùn)行時(shí)的處理: 某些注解可以在程序運(yùn)行的時(shí)候接受代碼的提取
    值得注意的是,注解不是代碼本身的一部分。

從官方的話我們可以看出注解的作用并不是來(lái)寫主要業(yè)務(wù)的,而是通過注解實(shí)現(xiàn)一些對(duì)代碼的處理。

如果大家用過LomBok在實(shí)體類上面加一個(gè)@Data就可以幫助我們生成實(shí)體類的get和set的方法,在或者說Swagger生成接口文檔,在對(duì)應(yīng)的接口上加上對(duì)應(yīng)的注解就可以實(shí)現(xiàn)生成對(duì)應(yīng)的接口文檔。注解只是起到到了標(biāo)簽的作用,具體的實(shí)現(xiàn)方式是有對(duì)應(yīng)的程序獲取到注解這個(gè)標(biāo)識(shí),然后去處理產(chǎn)生的。

那么我們可以用注解做什么呢?

現(xiàn)在我們就動(dòng)手寫一個(gè)自己的注解,通過這個(gè)注解來(lái)檢測(cè)程序是否報(bào)錯(cuò)。這是一個(gè)簡(jiǎn)單的小案例。

首先寫一個(gè)注解@Jiance

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Jiance {}

要測(cè)試的程序Cheshi并在方法上加上注解

public class Cheshi {@Jiancepublic void suanShu(){System.out.println("1234567890");}@Jiancepublic void jiafa(){System.out.println("1+1="+1+1);}@Jiancepublic void jiefa(){System.out.println("1-1="+(1-1));}@Jiancepublic void chengfa(){System.out.println("3 x 5="+ 3*5);}@Jiancepublic void chufa(){System.out.println("6 / 0="+ 6 / 0);}public void ziwojieshao(){System.out.println("我寫的程序沒有 bug!");} }

運(yùn)行檢測(cè)程序TestJiance

public class TestJiance {public static void main(String[] args) {Cheshi cheshi = new Cheshi();Class<Cheshi> cheshiClass = Cheshi.class;Method[] declaredMethods = cheshiClass.getDeclaredMethods();StringBuilder log = new StringBuilder();log.append("**************日志****************\n");int num = 0;for (Method declaredMethod : declaredMethods) {Jiance annotation = declaredMethod.getAnnotation(Jiance.class);if (annotation!=null){try {declaredMethod.setAccessible(true);declaredMethod.invoke(cheshi,null);} catch (Exception e) {num++;log.append(declaredMethod.getName()+":error:"+e.getCause().getMessage()+"\n");}}}log.append("cheshi has "+num+ " error");System.out.println(log);} }

執(zhí)行結(jié)果:

1+1=11 1234567890 1-1=0 3 x 5=15 **************日志**************** chufa:error:/ by zero cheshi has 1 error

這樣我們就成了這小的案例。我們通過我們自定義的注解,來(lái)檢測(cè)所有cheshi類中有錯(cuò)的方法。
注解的作用主要取決于你想用它做什么。

后續(xù)

利用反射獲取注解并實(shí)現(xiàn)功能通過上面已經(jīng)實(shí)現(xiàn)了,但是還有一種方式也可以獲取注解,并實(shí)現(xiàn)對(duì)應(yīng)的功能邏輯。
那就是利用Spring框架的Aop來(lái)實(shí)現(xiàn),AOP面向切面編程,我們可以利用AOP做很多事情。那如果AOP遇到注解會(huì)發(fā)生什么那。
下一篇我們利用自定義注解和Aop實(shí)現(xiàn)接口防刷的功能。也就是在一段時(shí)間內(nèi)如果大量訪問接口,就會(huì)觸發(fā)保護(hù)的一個(gè)案例。

End!!! 如有疑問請(qǐng)留言評(píng)論!

導(dǎo)航


接口防刷案例【傳送門】

總結(jié)

以上是生活随笔為你收集整理的啊啊,终于搞明白了,原来注解是这么一回事。6000+字理解注解【一】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。