日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

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

發布時間:2024/3/12 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 啊啊,终于搞明白了,原来注解是这么一回事。6000+字理解注解【一】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • 前言
    • 復習注解
      • 元注解
        • @Retention 存活時間
        • @Documented 文檔
        • @Target 目標
        • @Inherited 繼承
        • @Repeatable 可重復
      • 注解屬性
    • 注解實現-反射
      • 反射獲取注解方法
      • 注解的使用場景
      • 后續
      • 導航

前言

這兩天在gitHub上看一個開源項目,發現項目中有許多自定義注解。雖然在學JavaSE的時候學個注解,但是主要講的是如何自定義注解,和一些元注解的知識點。并沒有涉及到注解如何實現具體的功能。直到看到這個項目,突然醍醐灌頂。
由于篇幅過長,分成兩篇來寫。

復習注解

注解是在Java 1.5 的時候被引入的,注解的創建與接口十分相似。就是在interface關鍵字前面加一個@符號。

public @interface MyAnnotation{ }

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

元注解

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

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

@Retention 存活時間

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

下面看一下它的參數:

  • RetentionPolicy.SOURCE

注解只被保留到編譯階段,當編譯器編譯到它的時候看到參數為 RetentionPolicy.SOURCE會直接將其從源碼中剔除。

  • RetentionPolicy.SOURCE

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

  • RetentionPolicy.SOURCE

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

@Documented 文檔

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

@Target 目標

Target 有目標的意思,他的意思就是說,這個注解能夠使用的地方是哪里,是方法上、類上還是參數上。我們通過它的參數就可以進行設置。

參數作用
ElementType.ANNOTATION_TYPE可以使用在注解上
ElementType.CONSTRUCTOR可以在構造方法上使用
ElementType.FIELD可以在屬性上使用注解
ElementType.LOCAL_VARIABLE作用在局部變量上
ElementType.METHOD作用在方法上
ElementType.PACKAGE作用在包上
ElementType.PARAMETER作用在方法內的參數上
ElementType.TYPE可以給類型進行注解,比如類、接口、枚舉

@Inherited 繼承

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

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

@Repeatable 可重復

這個注解是在Java 1.8的時候加進來的。那可重復是什么意思那,就是說使用注解的時候可以同時使用多次注解。

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

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

注解屬性

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

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

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

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

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

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

這里還有一個注意點,如果注解中只有一個名字為value的屬性的時候,應用這個注解的時候可以直接填寫屬性值。

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

如果定義的這個注解中沒有屬性值,我們在使用注解的時候就不用在寫括號了

@MyAnnotation public void test(){ }

注解實現-反射

注解的知識經過上面的內容,應該能夠有個了解。那么我們定義好后注解,也是用了,但是并沒有什么實質的效果。哪有人該說了那定義有什么用?其實不然,如果真的沒有用那么Java官方就不會定義注解了。

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

我們可以通過反射獲取作用在類或者方法上的注解讓,后進行對應的處理。

反射獲取注解方法

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

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

然后通過getAnnotation()方法來獲取Annotation對象。

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

或者是getAnnotations()方法

public Annotation[] getAnnotations(){}

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

@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());}} }

運行結果:

id:101

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

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"; }

編寫測試類

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());} }

運行結果

Hi

這里需要注意一下,如果想要注解在運行時能夠獲取到,那么必須加上@Retention(RetentionPolicy.RUNTIME)這個注解參數,因為這個參數是指,注解能在jvm中被執行。

注解的使用場景

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

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

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

從官方的話我們可以看出注解的作用并不是來寫主要業務的,而是通過注解實現一些對代碼的處理。

如果大家用過LomBok在實體類上面加一個@Data就可以幫助我們生成實體類的get和set的方法,在或者說Swagger生成接口文檔,在對應的接口上加上對應的注解就可以實現生成對應的接口文檔。注解只是起到到了標簽的作用,具體的實現方式是有對應的程序獲取到注解這個標識,然后去處理產生的。

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

現在我們就動手寫一個自己的注解,通過這個注解來檢測程序是否報錯。這是一個簡單的小案例。

首先寫一個注解@Jiance

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

要測試的程序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!");} }

運行檢測程序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);} }

執行結果:

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

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

后續

利用反射獲取注解并實現功能通過上面已經實現了,但是還有一種方式也可以獲取注解,并實現對應的功能邏輯。
那就是利用Spring框架的Aop來實現,AOP面向切面編程,我們可以利用AOP做很多事情。那如果AOP遇到注解會發生什么那。
下一篇我們利用自定義注解和Aop實現接口防刷的功能。也就是在一段時間內如果大量訪問接口,就會觸發保護的一個案例。

End!!! 如有疑問請留言評論!

導航


接口防刷案例【傳送門】

總結

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

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