Java 注解详解 (annotation)
什么是java注解
注解是java5的新特性。注解可以看做一種注釋或者元數據(MetaData),可以把它插入到我們的java代碼中,用來描述我們的java類,從而影響java類的行為。
Java注解的目的
使用Java注解一般來說主要有三種目的
- 構建時指示: RetentionPolicy.SOURCE
- 編譯期指示: RetentionPolicy.CLASS
- 運行時指示: RetentionPolicy.RUNTIME
Java注解可以用在構建期。當構建我們的工程時,構建進程會編譯源碼、生成xml文件,打包編譯后的代碼和文件到jar包。構建過程一般由構建工具自動完成,常用的構建工具有ant、maven。構建工具在構建時會自動掃描我們的代碼,當遇到構建期注解時,會根據注解的內容生成源碼或者其它文件。
注解基本概念
注解的構成
一個java注解由一個@符后面跟一個字符串構成,類似于這樣:
@Entityjava注解中一般包含一些元素,這些元素類似于屬性或者參數,可以用來設置值,比如我們有一個包含兩個元素的@Entity注解:
@Entity(tableName = "vehicles", primaryKey = "id")上面注解中有兩個元素,tableName和primaryKey,它們各自都被賦予了自己的元素值。
注解的位置
注解可以用于描述一個類、接口、方法、方法參數、字段、局部變量等。在下邊這個例子中,注解分別用在了類、字段、方法、參數和局部變量中:
//注解一個類 @Entity public class Vehicle {//注解一個字段@Persistentprotected String vehicleName = null;//注解一個方法@Getterpublic String getVehicleName() {return this.vehicleName;}//注解一個參數public void setVehicleName(@Optional vehicleName) {this.vehicleName = vehicleName;}public List addVehicleNameToList(List names) {//注解一個局部變量@OptionalList localNames = names;if(localNames == null) {localNames = new ArrayList();}localNames.add(getVehicleName());return localNames;} }一些常用的內置注解
Java本身提供了三個內置注解,他們分別是:
1. @Deprecated 2. @Override 3. @SuppressWarnings@Deprecated注解
@Deprecated可以用來描述一個類、方法或者字段,表示java不贊成使用這些被描述的對象,如果我們使用了這些類、方法或者字段,編譯器會給我們警告。@Deprecated注解使用方法如下:
@Deprecated public class MyComponent { }在我們實際應用中,在使用@Deprecated注解時,最好同時使用Java Doc的@deprecated符號,用來描述當前類、方法或者字段是不贊成使用的,并且告訴開發者應該用哪個對象替換,如下面例子:
@Deprecated /**@deprecated Use MyNewComponent instead. */ public class MyComponent {}@Override注解
@Override注解是一個編譯時注解,它主要用在一個子類的方法中,當被注解的子類的方法在父類中找不到與之匹配的方法時,編譯器會報錯。 當我們在子類中覆蓋父類的方法時,就要用到@Override注解,這樣,如果父類中的方法名稱或參數發生改變時,如果子類沒有做相應的調整編譯器便會報錯,這就是@Override注解所起到的作用。當然@Override注解不是強制使用的,但我還是推薦大家盡量使用它。下面是一個@Override注解的例子:
public class MySuperClass {public void doTheThing() {System.out.println("Do the thing");} }public class MySubClass extends MySuperClass{@Overridepublic void doTheThing() {System.out.println("Do it differently");} }@SuppressWarnings
@SuppressWarnings注解的作用是使編譯器忽略掉編譯器警告。比如,如果我們的一個方法調用了一個@Deprecated方法,或者做了一個不安全的類型轉換,此時編譯器會生成一個警告。如果我們不想看到這些警告,我們就可以使用@SuppressWarnings注解忽略掉這些警告:
@SuppressWarnings public void methodWithWarning() {}創建自定義注解
定義一個自定義注解
從上面內置注解可以看到,注解很方便也很有用,很多時候我們也需要創建我們自己的注解。創建注解其實和創建類或接口一樣簡單:
@interface MyAnnotation {String value();String name();int age();String[] newNames(); }上面代碼便創建了一個@MyApplication注解,它一共有四個元素。@interface關鍵字就代表這是一個注解類型,所以使用@interface關鍵字就可以創建注解了。
需要注意的是,注解中的每個元素定義類似于接口中的方法定義。每個元素定義包含一個數據類型和名稱,注解元素的數據類型可以是java基本數據類型、String、數組,但不能是復雜對象類型。
下面這段代碼演示了如何使用注解:
@MyAnnotation(value="123",name="Jakob",age=37,newNames={"Jenkov", "Peterson"} ) public class MyClass {}給注解元素設置默認值
我們可以通過default關鍵字為某個元素設置默認值,當一個元素被設置默認值之后,這個元素便成了注解的可選元素。?
下面我們為@MyAnnotation注解的value元素設置一個默認值:
當value元素設置默認值之后,再使用時我們就可以省略掉value元素,此時的value值采用的是默認值:
@MyAnnotation(name="Jakob",age=37,newNames={"Jenkov", "Peterson"} ) public class MyClass {}兩個元注解:@Retention和@Target
元注解就是注解的注解。我們可以通過元注解來控制描述我們自定義注解的行為。
@Retention
@Retention用來定義當前注解的作用范圍,如果我們要把我們的自定義注解限制為運行時有效,那么我們可以使用@Retention注解進行指定:
import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy;@Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation {String value() default "";}注意@MyAnnotation注解上面的@Retention的值:
@Retention(RetentionPolicy.RUNTIME)上面這個注解會告訴編譯器和JVM,這個注解需要在運行時有效,JVM會在運行時通過反射機制獲取注解信息,關于如何在運行時利用反射獲取注解信息,最后面會進行介紹。@Retention注解的值一共有三種:
- RetentionPolicy.SOURCE :?注解只存在于源碼中,不會存在于.class文件中,在編譯時會被忽略掉
- RetentionPolicy.CLASS:注解只存在于.class文件中,在編譯期有效,但是在運行期會被忽略掉,這也是默認范圍
- RetentionPolicy.RUNTIME:在運行期有效,JVM在運行期通過反射獲得注解信息
@Target
@Target注解用來約束自定義注解可以注解Java的哪些元素。比如下面這個例子:
import java.lang.annotation.ElementType; import java.lang.annotation.Target;@Target({ElementType.METHOD}) public @interface MyAnnotation {String value(); }這個例子中,@Target的值是ElementType.METHOD,通過它的名稱可以看出,這個自定義注解只能注解類的方法。
ElementType的值一共有以下幾種:
- ElementType.ANNOTATION_TYPE
- ElementType.CONSTRUCTOR
- ElementType.FIELD
- ElementType.LOCAL_VARIABLE
- ElementType.METHOD
- ElementType.PACKAGE
- ElementType.PARAMETER
- ElementType.TYPE
其中大部分通過名字就能看出它的作用,不過有兩個需要單獨介紹一下:
- ElementType.ANNOTATION_TYPE:元注解類型,只能用來注解其它的注解,例如@Target和@Retention。
- ElementType.TYPE:可以用來注解任何類型的java類,如類、接口、枚舉、或者注解類。
@Inherited
@Inherited注解表示當前注解會被注解類的子類繼承。比如有一個自定義注解:
java.lang.annotation.Inherited@Inherited public @interface MyAnnotation {}如果有一個類使用了上面這個注解:
@MyAnnotation public class MySuperClass { ... }那么這個類的子類也會繼承這個注解:
public class MySubClass extends MySuperClass { ... }因為MySubClass?繼承了MyClass,而MyClass的注解@MyAnnotation是可繼承的,最終MySubClass也會有@MyAnnotation注解。
@Documented
@Documented的作用是告訴JavaDoc工具,當前注解本身也要顯示在Java Doc中。比如我們用@Document注解了我們的自定義注解:
import java.lang.annotation.Documented;@Documented public @interface MyAnnotation {}如果一個類使用了這個注解:
@MyAnnotation public class MySuperClass { ... }那么當生成MySuperClass的JavaDoc的時候,@MyAnnotation也會出現在JavaDoc當中。
通過反射獲得Java注解信息
上面對注解做了一個詳細介紹,具體該如何使用我們的自定義注解呢?其實在現實應用中,我們的自定義注解一般都是起到運行時指示的作用,也就是運行時注解。對于運行時注解,我們可以通過反射機制獲得注解信息。
比如我們有一個自定義注解:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface MyAnnotation {public String name();public String value(); }并用這個注解注解了一個類:
@MyAnnotation(name = "hello name",value = "hello value") public class MyClass {}獲取類的注解信息
public class TestAnnotation {public static void main(String[] args) {//通過反射獲得MyClass的注解信息MyAnnotation myAnnotation=MyClass.class.getAnnotation(MyAnnotation.class);System.out.println(myAnnotation.name());System.out.println(myAnnotation.value());} }獲取方法的注解信息
public class TestAnnotation {public static void main(String[] args) {Method method = null;try {method = MyClassB.class.getMethod("method");Annotation annotation = method.getAnnotation(MyAnnotation.class);if (annotation !=null) {MyAnnotation myAnnotation = (MyAnnotation) annotation;System.out.println("name: " + myAnnotation.name());System.out.println("value: " + myAnnotation.value());}} catch (NoSuchMethodException e) {e.printStackTrace();}} }獲取參數的注解信息
Method method = ... //obtain method object Annotation[][] parameterAnnotations = method.getParameterAnnotations(); Class[] parameterTypes = method.getParameterTypes();int i=0; for(Annotation[] annotations : parameterAnnotations){Class parameterType = parameterTypes[i++];for(Annotation annotation : annotations){if(annotation instanceof MyAnnotation){MyAnnotation myAnnotation = (MyAnnotation) annotation;System.out.println("param: " + parameterType.getName());System.out.println("name : " + myAnnotation.name());System.out.println("value: " + myAnnotation.value());}} }獲取字段的注解信息
Field field = ... // obtain method object Annotation annotation = field.getAnnotation(MyAnnotation.class);if(annotation instanceof MyAnnotation){MyAnnotation myAnnotation = (MyAnnotation) annotation;System.out.println("name: " + myAnnotation.name());System.out.println("value: " + myAnnotation.value()); } from: https://yq.aliyun.com/articles/65139?spm=5176.100239.blogcont61791.36.xwqy99總結
以上是生活随笔為你收集整理的Java 注解详解 (annotation)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java中Comparable和Comp
- 下一篇: Java魔法堂:注解用法详解——@Sup