1. 註解基本概念 註解,什麼是註解? 打開百度搜索 好,看不懂 沒關係 一步一步慢慢來 先不管註解,註釋這個概念應該就很熟悉了,文檔註釋,單行註釋,多行註釋 註釋是對一段程式,一個方法,一個類進行描述,是給我們程式員看的,都知道,註解是不會被編譯的,會被忽略 註解,同樣的道理,其實就是用來說明代碼 ...
1. 註解基本概念
註解,什麼是註解?
打開百度搜索
好,看不懂
沒關係
一步一步慢慢來
先不管註解,註釋這個概念應該就很熟悉了,文檔註釋,單行註釋,多行註釋
註釋是對一段程式,一個方法,一個類進行描述,是給我們程式員看的,都知道,註解是不會被編譯的,會被忽略
註解,同樣的道理,其實就是用來說明代碼的,但是註解是 給電腦看的,是會被編譯的
因此:
註解概念:jdk1.5之後出現,是對程式進行說明,並且會被編輯,給電腦看的
來看看toString 方法
Override 這個單詞並不陌生java基礎—重寫、重載 ,沒錯 重寫,子類重寫父類的方法
如果我們 把這個方法改一下
可以看到註解 報錯了 錯誤信息:
方法不是重寫父類的方法
就像我們之前說的函數式介面 java8 (jdk 1.8) 新特性——Lambda
@FunctionalInterface 註解一樣
所以註解的其中一個功能就出來了: 用來校驗,編譯檢查
註解的格式:@+名稱
2. JDK 中的內置註解
java提供了5個基本的註解:
這五個註解的介紹百度百科已經說的很清楚了,這邊直接引用
限定父類重寫方法:@Override
當子類重寫父類方法時,子類可以加上這個註解,那這有什麼什麼用?這可以確保子類確實重寫了父類的方法,避免出現低級錯誤
2. 標示已過時:@Deprecated
這個註解用於表示某個程式元素類,方法等已過時,當其他程式使用已過時的類,方法時編譯器會給出警告(刪除線,這個見了不少了吧)。
3.抑制編譯器警告:@SuppressWarnings
被該註解修飾的元素以及該元素的所有子元素取消顯示編譯器警告,例如修飾一個類,那他的欄位,方法都是顯示警告
4.“堆污染”警告與@SafeVarargs
想理解這個就要明白什麼是堆污染,堆污染是什麼?
其實很好理解,就是把不帶泛型的對象賦給一個帶泛型的對象,為什麼不行?很簡單,因為不帶泛型的話,預設會給泛型設定為object,意思就是什麼類型都可以往裡面塞,那你一個不帶泛型的怎麼可能給一個帶泛型塞呢。
例如運行如下代碼:
List list = new ArrayList(); list.add(20);
List<String> ls = list; System.out.println(ls.get(0));
則會拋出堆污染異常Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String at Test.Test1.main(Test1.java:29)
註意:可變參數更容易引發堆污染異常,因為java不允許創建泛型數組,可變參數恰恰是數組。
抑制這個警告的方法有三個:
1.@SafeVarargs修飾引發該警告的方法或構造器
2.使用@suppressWarnings("unchecked")
3.編譯時使用-Xlint:varargs
5.函數式介面與@Functionallnterface
什麼是函數式?如果介面中只有一個抽象方法(可以包含多個預設方法或多個static方法)
介面體內只能聲明常量欄位和抽象方法,並且被隱式聲明為public,static,final。
介面裡面不能有私有的方法或變數。
這個註解有什麼用?這個註解保證這個介面只有一個抽象方法,註意這個只能修飾介面
認識認識,有個印象
3.註解的功能
-
首先一個就是前邊的 用來編譯檢查功能
-
其次,註解還有編寫文檔的功能
什麼?編寫文檔,一臉懵逼,別急,看看就知道了
jdk 文檔,應該程式員人手都有一份,沒有的伙伴 公眾號內回覆【文檔】 獲取
其實這些文檔就是通過註解生成的
事實勝於雄辯
我們先建一個類
桌面新建一個文件夾 api ,把這個類拷貝進去
cmd 然後進行javadoc 命令
可以看到生成了一堆文件,
雙擊打開index.html
是不是發現新大陸!!
-
再者,就是代碼分析【這個就是最重要的了,Spring Aop 自定義註解都是這個用的這個功能,當然主要原理還是反射】 java進階—反射
4. 註解本質
前邊 說了,註解語法格式:@+名稱
那麼,是不是只要我們 @ +隨便一個名字是不是就是註解呢?@OpLog
@UserLog
你當然可以這樣定義,但並不是按照這種格式寫了,編譯器就能認,它背後是有進行一些操作的,也就是說讓編譯器認你寫的這個是註解
照貓畫虎,我們來看官方是怎麼處理的
點開註解原碼
格式:
元註解 public @interface 註解名稱 { }
@interface 是什麼意思
現在我隨便寫了一個類
public @interface MyAnnotation { }
進行反編譯
可以看到 @interface 註解的本質就是 interface ,只不過繼承了 lang 包的一個類 java.lang.annotation.Annotation
看看api ,Api 公眾號內 回覆 【文檔】 獲取
5. 註解屬性
我們都知道,介面中可以定義抽象方法,這邊叫做註解的屬性
屬性的返回值類型是有要求的
-
八大基本類型
-
枚舉
-
String 類型
-
註解
-
Class
-
以上類型的數組
註意: 返回值類型不能是 void 跟 類 類型
可以看到報錯了
使用註解,並且對屬性賦值就很簡單了,前邊說了,註解可以在一個類,一個方法上進行標記
可以看到這是我們剛剛定義的屬性,屬性名 = 值 就行了 , 值要跟類型對應上,並且有幾個屬性,就要寫幾個,不然會報錯
6. 值獲取
註解值獲取得通過反射獲取,前提是註解上有保留策略,也就是必須要有元註解,這邊先不管是什麼東西,為了演示獲取值我們先加上
運行結果
7.元註解
最後來看元註解
我們知道註解是用來描述程式的
@Retention 這個註解 ,現在把它看做一個程式【只不過這個程式是註解程式】, 那麼在它上面的註解是用來描述這個 @Retention 註解程式的
因此:元註解的概念就出來了
元註解:描述註解的註解
按住alt點擊target,可以看到target 註解上面又有元註解,套娃
![](https://img2023.cnblogs.com/blog/1813348/202212/1813348-20221221144238958-544714903.png)
那麼元註解有哪些,JDK給我們定義好了
@Target : 表示註解能夠作用在什麼位置【類,方法 等等】
@Retention: 描述註解被保留的階段【java代碼的三個階段】
@Document 描述註解是否抽取到Api文檔中
@Inherited: 註解是否被子類繼承 【加上這個標記,子類會自動繼承父類中的註解】
@Repeatable:java8新增的註解,用於開發重覆註解
類型註解;這個也是java8新增的註解,可以用在任何用到類型的地方【其實也就是target 的枚舉增加的枚舉類值】
-
@Target :
點開原碼,我們可以看到,target 只有一個屬性,這個屬性是枚舉數組,
![](https://img2023.cnblogs.com/blog/1813348/202212/1813348-20221221144300174-1383774402.png)
點開ElementType 就可以看到這就是一個枚舉
![](https://img2023.cnblogs.com/blog/1813348/202212/1813348-20221221144308373-466072420.png)
因此,元註解 @Target 就可以這樣寫
可以看到枚舉類中不只有一個 TYPE 屬性,有這個多,我們先註重以下三種就行了,java8 新加的類型註解後面再提
-
ElementType.TYPE: 表示這個註解只能作用在類上
可以看到成員變數跟方法上都報錯
![](https://img2023.cnblogs.com/blog/1813348/202212/1813348-20221221144338214-1740491493.png)
-
ElementType.METHOD :可以作用於方法上
-
ElementType.FIELD:可以作用於成員變數
這兩個就不分別單獨演示了,跟在類上單獨一個意思
我們全都加上看看
可以看到成員變數跟方法上都可以使用這個註解
2. @Retention
同樣有一個枚舉屬性
只有三個,這就是java代碼三個階段了 ,從上到下分別表示,源代碼(.java), .class ,以及運行時階段 ,我們自定義 一般都是 採用 RUNTIME
source: 位元組碼文件都不存在被描述的註解
class: 被描述的註解,會保留到class位元組碼文件,不會被JVM讀取
runtime: 被描述的註解,會保留class位元組碼文件, 會被JVM讀取
3. @Document :就使用前邊的javadoc 命令,被註解的註解可以保存在java API文檔中
4. @Inherited :就是子類也能獲取父類 定義的 註解 屬性的值
父類:
/** * @author java資訊 * @since 2011-11-24 */ @MyAnnotation(name = "父類的zhangsan") public class TestApi { }
子類:
package com.test1.api; public class Test2 extends TestApi{ public static void main(String[] args) { MyAnnotation annotation = Test2.class.getAnnotation(MyAnnotation.class); System.out.println(annotation.name()); } }
5. @Repeatable:可以重覆使用一個註解
這個剛好也是前面沒提到的 class 類型
沒加之前
現在我們先定義一個容器註解,也就是註解 屬性 是 註解數組
@Target(ElementType.TYPE) @Documented @Inherited @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation2 { MyAnnotation[] value(); }
接著 加上
可以看到可以使用重覆註解了
@MyAnnotation(name = "zhangsan 1 ") @MyAnnotation(name = "zhangsan 2") public class TestApi { public static void main(String[] args) { MyAnnotation[] annotationsByType = TestApi.class.getAnnotationsByType(MyAnnotation.class); for (MyAnnotation an : annotationsByType) { System.out.println(an.name()); } } }
6. 類型註解
java8 新加的,在target 枚舉屬性中新加的枚舉值,這兩個
一般都是使用 TYPE_USER 就夠了,表示註解可以使用在任何地方
比如:lombok 中的@ NonNull註解
我們就可以使用在參數前面
以上就是註解全部內容了,最後最後最後!!!別忘了,公眾號回覆【文檔】 獲取api ,感謝閱讀