Java中的注解詳解(Annotation)
所有的注解類型都繼承自 java.lang.annotation.Annotation 接口。
注解(Annotation)是一種引用數(shù)據(jù)類型。編譯之后也是生成 xxx.class 文件。
一個注解準(zhǔn)確意義上來說,只不過是一種特殊的注釋而已,如果沒有解析它的代碼,它可能連注釋都不如。
解析一個類或者方法的注解往往有兩種形式
一種是編譯期直接的掃描。=====> @Retention(RetentionPolicy.SOURCE)
- 編譯器的掃描指的是編譯器在對 java 代碼編譯字節(jié)碼的過程中會檢測到某個類或者方法被一些注解修飾,這時它就會對于這些注解進(jìn)行某些處理。典型的就是 @Override 注解。
- 這一種情況只適用于那些編譯器已經(jīng)熟知的注解類,比如 JDK 內(nèi)置的幾個注解,而你自定義的注解,編譯器是不知道你這個注解的作用的,當(dāng)然也不知道該如何處理,往往只是會根據(jù)該注解的作用范圍來選擇是否編譯進(jìn)字節(jié)碼文件,僅此而已。
一種是運行期反射。====> @Retention(RetentionPolicy.RUNTIME)
一、元注解
- 元注解是用于修飾注解的注解,通常用在注解的定義上。
- 元注解一般用于指定某個注解生命周期以及作用目標(biāo)等信息。
Java 中的元注解
@Target:注解的作用目標(biāo)
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/**
* Returns an array of the kinds of elements an annotation interface
* can be applied to.
* @return an array of the kinds of elements an annotation interface
* can be applied to
*/
ElementType[] value();
}ElementType.TYPE:允許被修飾的注解作用在類、接口和枚舉上ElementType.FIELD:允許作用在屬性字段上ElementType.METHOD:允許作用在方法上ElementType.PARAMETER:允許作用在方法參數(shù)上ElementType.CONSTRUCTOR:允許作用在構(gòu)造器上ElementType.LOCAL_VARIABLE:允許作用在本地局部變量上ElementType.ANNOTATION_TYPE:允許作用在注解上ElementType.PACKAGE:允許作用在包上
@Retention:注解的生命周期
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}RetentionPolicy.SOURCE:當(dāng)前注解編譯期可見,不會寫入 class 文件RetentionPolicy.CLASS:類加載階段丟棄,會寫入 class 文件RetentionPolicy.RUNTIME:永久保存,可以反射獲取
@Documented:注解是否應(yīng)當(dāng)被包含在 JavaDoc 文檔中
@Inherited:是否允許子類繼承該注解
二、Java 中內(nèi)置的三大注解
@Override
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}它沒有任何的屬性,所以并不能存儲任何其他信息。它只能作用于方法之上,編譯結(jié)束后將被丟棄。
僅被編譯器可知,編譯器在對 java 文件進(jìn)行編譯成字節(jié)碼的過程中,一旦檢測到某個方法上被修飾了該注解,就會去匹對父類中是否具有一個同樣方法簽名的函數(shù),如果不是,自然不能通過編譯。
@Deprecated
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE})
public @interface Deprecated {
String since() default "";
boolean forRemoval() default false;
}可以修飾所有的類型,作用是,標(biāo)記當(dāng)前的類或者方法或者字段等已經(jīng)不再被推薦使用了,可能下一次的 JDK 版本就會刪除。
@SuppressWarnings
三、自定義注解
語法格式:
[修飾符列表] @interface 注解類型名{
類型 屬性() [defauult 值];
}
// 樣例
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String name() default "gdb";
String[] phoneNumbers() default {};
}注解當(dāng)中的屬性類型可以是:byte short int long float double boolean char String Class 枚舉類型以及以上每一種的數(shù)組形式。
四、反射注解
要求必須使用 @Retention(RetentionPolicy.RUNTIME),這樣該注解才能夠被反射到。
例子:反射類上的 @MyAnnotation 注解。
- 1.編寫自己的注解:
package annotation1;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String name() default "gdb";
String[] phoneNumbers() default {};
} - 2.在類上使用自己的注解:
package annotation1;
@MyAnnotation(name = "zhangsan", phoneNumbers = {"123456", "654321"})
public class MyAnnotationTest {
}- 3.通過反射機制來獲取指定類上的注解信息:
package annotation1;
import java.util.Arrays;
public class ReflectAnnotation {
public static void main(String[] args) throws Exception {
//獲取類
Class<?> c = Class.forName("annotation1.MyAnnotationTest");
//判斷類上面是否有 @MyAnnotation
if (c.isAnnotationPresent(MyAnnotation.class)){
//獲取注解對象
MyAnnotation myAnnotation = (MyAnnotation)c.getAnnotation(MyAnnotation.class);
//獲取注解對象的屬性和調(diào)用接口沒有區(qū)別
System.out.println(myAnnotation.name() + ", " + Arrays.toString(myAnnotation.phoneNumbers()));
}
//判斷 Date 類上面是否有 @MyAnnotation 這個注解。
Class<?> s = Class.forName("java.lang.String");
System.out.println(s.isAnnotationPresent(MyAnnotation.class));
}
}
五、注解的作用
注解在程序當(dāng)中等同于一種標(biāo)記,如果這個元素上有這個注解怎么辦,沒有這個注解怎么辦。
應(yīng)用場景:假設(shè)有這樣一個注解,叫做 @Id,這個注解只能出現(xiàn)在類上面,當(dāng)這個類上有這個注解的時候,要求這個類中必須有一個 int 類型的 id 屬性。如果沒有這個屬性就報異常。如果有這個屬性就正常執(zhí)行。
- 1.編寫 @Id 注解:
package annotation1;
public class NotHasIdException extends RuntimeException{
public NotHasIdException() {
}
public NotHasIdException(String message) {
super(message);
}
}- 2.編寫異常類:
package annotation1;
public class NotHasIdException extends RuntimeException{
public NotHasIdException() {
}
public NotHasIdException(String message) {
super(message);
}
}
- 3.編寫使用 @Id 注解的類:
package annotation1;
@Id
public class IdAnnotationTest {
int id;
}
- 4.通過反射機制來判斷是否正確:
package annotation1;
import java.lang.reflect.Field;
public class ReflectAnnotation {
public static void main(String[] args) throws Exception {
//獲取類
Class<?> c = Class.forName("annotation1.IdAnnotationTest");
//判斷類上面是否有 @Id 注解
if (c.isAnnotationPresent(Id.class)){
//當(dāng)一個類上面有 @Id 注解的時候,要求類中必須存在 int 類型的id屬性。
//如果沒有int類型的id屬性則報異常。
//獲取類的所有屬性
Field[] fields = c.getDeclaredFields();
boolean isOK = false;
for(Field field : fields){
if("id".equals(field.getName()) && "int".equals(field.getType().getSimpleName())){
isOK = true;
break;
}
}
//判斷是否合法
if (!isOK)
throw new NotHasIdException("被@Id注解標(biāo)注的類沒有int類型的id屬性?。?!");
}
}
}
六、總結(jié)
- 如果一個注解的屬性的名字是 value,并且只有一個屬性的話,在使用的時候,該屬性名可以省略。
- 如果屬性是一個數(shù)組,如果數(shù)組中只有一個元素,大括號可以省略。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解Java的MyBatis框架中的緩存與緩存的使用改進(jìn)
很多人在使用MyBatis的緩存后經(jīng)常會遇到MySQL分頁查詢的顯示問題,針對于此,這里我們就來詳解Java的MyBatis框架中的緩存與緩存的使用改進(jìn),首先來回顧一下MyBatis的緩存機制與執(zhí)行:2016-06-06
Springboot詳解RocketMQ實現(xiàn)消息發(fā)送與接收流程
這篇文章主要介紹了SpringBoot整合RocketMQ實現(xiàn)消息發(fā)送和接收功能,我們使用主流的SpringBoot框架整合RocketMQ來講解,使用方便快捷,本文分步驟給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-06-06
詳解Java如何在業(yè)務(wù)代碼中優(yōu)雅的使用策略模式
這篇文章主要為大家介紹了Java如何在業(yè)務(wù)代碼中優(yōu)雅的使用策略模式,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價值,感興趣的可以了解下2023-08-08
在lambda的foreach遍歷中break退出操作(lambda foreach break)
這篇文章主要介紹了在lambda的foreach遍歷中break退出操作(lambda foreach break),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09
springboot開發(fā)擴展springmvc實現(xiàn)解析
這篇文章主要介紹了springboot開發(fā)擴展springmvc實現(xiàn)解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-02-02
java編程實現(xiàn)基于UDP協(xié)議傳輸數(shù)據(jù)的方法
這篇文章主要介紹了java編程實現(xiàn)基于UDP協(xié)議傳輸數(shù)據(jù)的方法,較為詳細(xì)的分析了UDP協(xié)議的原理及Java編程實現(xiàn)數(shù)據(jù)傳輸客戶端與服務(wù)器端的相關(guān)技巧,需要的朋友可以參考下2015-11-11
MyBatis-Plus 批量插入數(shù)據(jù)的操作方法
spring boot+mybatis plus環(huán)境,單條插入用的是BaseMapper自帶的insert方法,本文重點給大家介紹MyBatis-Plus 批量插入數(shù)據(jù)的操作方法,感興趣的朋友一起看看吧2021-09-09

