Java註解能夠想象成代碼是具備生命的,註解就是對於代碼中的某些鮮活的個體貼上一張標籤。簡單的說,註解就如同一張標籤
。java
元註解是能夠註解到註解上的註解,或者說元註解是一種基本註解,可是它可以應用到其它的註解上面。程序員
其實說白了,元註解也是一張標籤,可是它是一張特殊的標籤,它的做用和目的就是給其餘普通的標籤進行解釋說明的
。數組
@Documented安全
若是使用
@Documented
修飾Annotation
,則表示它能夠出如今javadoc中。 定義Annotation時,@Documented無關緊要
;若沒有定義,則Annotation不會出如今javadoc中。bash
@Retentionide
Retention 的英文意爲保留期的意思。當 @Retention 應用到一個註解上的時候,它解釋說明了這個註解的的存活時間。定義Annotation時,
@Retention無關緊要
。若沒有@Retention,則@Retention的默認取值是RetentionPolicy.CLASS
。函數它的取值以下:工具
- RetentionPolicy.SOURCE 註解只在源碼階段保留,在編譯器進行編譯時它將被丟棄並忽視。
- RetentionPolicy.CLASS 註解只被保留到編譯進行的時候,在加載到 JVM 以前進行丟棄並忽略,即不會加載到JVM中。。
- RetentionPolicy.RUNTIME 註解能夠保留到程序運行的時候,它會被加載進入到 JVM 中,因此在程序運行時能夠獲取到它們。
@Targetui
Target 是目標的意思,@Target 指定了註解運用的地方。 定義Annotation時,
@Target無關緊要
。如有@Target,則該Annotation只能用於它所指定的地方;若沒有@Target,則該Annotation能夠用於任何地方。spa你能夠這樣理解,當一個註解被 @Target 註解時,這個註解就被限定了運用的場景。
@Target 有下面的取值
- ElementType.PACKAGE 能夠給一個包進行註解
- ElementType.ANNOTATION_TYPE 能夠給一個註解進行註解
- ElementType.TYPE 能夠給一個類型進行註解,好比類、接口、枚舉
- ElementType.CONSTRUCTOR 能夠給構造方法進行註解
- ElementType.FIELD 能夠給屬性進行註解
- ElementType.METHOD 能夠給方法進行註解
- ElementType.PARAMETER 能夠給一個方法內的參數進行註解
- ElementType.LOCAL_VARIABLE 能夠給局部變量進行註解
@Repeatable
Repeatable 天然是可重複的意思.是指由另外一個註解來存儲重複註解,在使用的時候,用存儲註解來擴展重複註解。
建立重複註解Authority時,加上@Repeatable,指向存儲註解Authorities,在使用時候,直接能夠重複使用Authority註解。 ![]()
@Inherited
@Inherited 元註解是一個標記註解,@Inherited闡述了某個被標註的類型是被繼承的。若是一個使用了@Inherited修飾的annotation類型被用於一個class,則這個annotation將被用於該class的子類。
注意:@Inherited annotation類型是被標註過的class的子類所繼承。類並不從它所實現的接口繼承annotation,方法並不從它所重載的方法繼承annotation。
當@Inherited annotation類型標註的annotation的Retention是RetentionPolicy.RUNTIME,則反射API加強了這種繼承性。若是咱們使用java.lang.reflect去查詢一個@Inherited annotation類型的annotation時,反射代碼檢查將展開工做:檢查class和其父類,直到發現指定的annotation類型被發現,或者到達類繼承結構的頂層。
由於日常開發少見使用註解,致使有很多人認爲註解的地位不高。其實Annotation
同 classs
和 interface
同樣,註解也是一種類型,只不過它是在 Java SE 5.0 版本中才開始引入的概念。
一個Annotation
和一個@Retention中的RetentionPolicy
關聯,即每一個Annotation
,都會有惟一的RetentionPolicy
的屬性。
1個Annotation
和 1~n個@Target中的ElementType
關聯,即對於每1個Annotation對象
,能夠有若干個@Target的ElementType
屬性值。
示例:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
public @interface AnnotationTest {
}
複製代碼
上面的示例,使用
@Documented
說明能夠出如今Java文檔中,@Retention(RetentionPolicy.RUNTIME)
說明AnnotationTest能夠加載到JVM 中,能夠在程序運行的時候的時候經過反射獲取到。@Target(value = {ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})說明AnnotationTest能夠用於註解,類和接口,方法,屬性中。
註解經過 @interface
關鍵字進行定義。自動繼承了java.lang.annotation.Annotation
接口,由編譯程序自動完成其餘細節
不能繼承其餘的註解或接口
。@interface
用來聲明一個註解,其中的每個方法實際上至關於一個配置參數
。方法的名稱就是參數的名稱
,返回值類型就是參數的類型
。default
來聲明參數的默認值。第一,只能用public
或default
這兩個訪問權修飾.例如,String value();
這裏把方法設爲defaul默認類型;
第二,參數成員只能使用註解參數支持的數據類型
第三,若是隻有一個參數成員,最好把參數名稱設爲value
,後加小括號
.
註解元素必須有肯定的值
,要麼在定義註解的默認值中指定,要麼在使用註解時指定,非基本類型的註解元素的值不可爲null。所以, 使用空字符串或0做爲默認值是一種經常使用的作法。這個約束使得處理器很難表現一個元素的存在或缺失的狀態,由於每一個註解的聲明中,全部元素都存在,而且都具備相應的值,爲了繞開這個約束,咱們只能定義一些特殊的值,例如空字符串或者負數,一次表示某個元素不存在,在定義註解時,這已經成爲一個習慣用法。
定義了註解,並在須要的時候給相關類,類屬性加上註解信息,若是沒有相應的註解信息處理流程,註解能夠說是沒有實用價值。如何讓註解真真的發揮做用,主要就在於註解處理方法。
若是沒有用來讀取註解的方法和工做,那麼註解也就不會比註釋更有用處了。使用註解的過程當中,很重要的一部分就是建立於使用註解處理器。Java SE5擴展了反射機制的API,以幫助程序員快速的構造自定義註解處理器。
簡單的自定義註解和使用註解實例:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
public @interface AnnotationTest {
/***
* 實體默認firstLevelCache屬性爲false
* @return boolean
*/
boolean firstLevelCache() default false;
/***
* 實體默認secondLevelCache屬性爲false
* @return boolean
*/
boolean secondLevelCache() default true;
/***
* 表名默認爲空
* @return String
*/
String tableName() default "";
/***
* 默認以""分割註解
*/
String split() default "";
}
複製代碼
它的形式跟接口很相似,只不過前面多了一個@
符號。經過上面的語句,就能夠建立一個名爲AnnotationTest
的註解。
@AnnotationTest
public class Test {
}
複製代碼
上面的代碼,建立一個類 Test,
而後在類定義的地方加上 @AnnotationTest
就能夠用 AnnotationTest
註解這個類了。能夠簡單的理解爲將AnnotationTest
這張標籤貼到 Test 這個類上面。
這個元素是用來標記過期的元素
。編譯器在編譯階段遇到這個註解時會發出提醒警告,告訴開發者正在調用一個過期的元素好比過期的方法、過期的類、過期的成員變量。
使用以下
public class Hero {
@Deprecated
public void say(){
System.out.println("Noting has to say!");
}
public void speak(){
System.out.println("I have a dream!");
}
}
複製代碼
在IDE中調用hero.say()時,say()方法的上面會有方法過期的提醒。
這個你們應該很熟悉了,提示子類要複寫父類中被 @Override 修飾的方法
阻止警告的意思。以前說過調用被 @Deprecated 註解的方法後,編譯器會警告提醒,而有時候開發者會忽略這種警告,他們能夠在調用的地方經過 @SuppressWarnings 達到目的。
參數安全類型註解。它的目的是提醒開發者不要用參數作一些不安全的操做,它的存在會阻止編譯器產生 unchecked 這樣的警告。
@SafeVarargs // Not actually safe!
static void m(List<String>... stringLists) {
Object[] array = stringLists;
List<Integer> tmpList = Arrays.asList(42);
array[0] = tmpList; // Semantically invalid, but compiles without warnings
String s = stringLists[0].get(0); // Oh no, ClassCastException at runtime!
}
複製代碼
函數式接口 (Functional Interface) 就是一個只具備一個方法的普通接口。
例如:
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's * <code>run</code> method to be called in that separately executing * thread. * <p> * The general contract of the method <code>run</code> is that it may * take any action whatsoever. * * @see java.lang.Thread#run() */ public abstract void run(); } 複製代碼
可能有人會疑惑,函數式接口標記有什麼用,這個緣由是函數式接口能夠很容易轉換爲 Lambda 表達式
Java使用Annotation接口來表明程序元素前面的註解,該接口是全部Annotation類型的父接口。除此以外,Java在java.lang.reflect 包下新增了AnnotatedElement
接口,該接口表明程序中能夠接受註解的程序元素,該接口主要有以下幾個實現類:
java.lang.reflect 包下主要包含一些實現反射功能的工具類,實際上,java.lang.reflect 包全部提供的反射API擴充了運行時讀取Annotation信息的能力。當一個Annotation類型被定義爲運行時的Annotation後,該註解才能是運行時可見,當class文件被裝載時被保存在class文件中的Annotation纔會被虛擬機讀取。
AnnotatedElement
接口是全部程序元素(Class、Method和Constructor)的父接口,因此程序經過反射獲取了某個類的AnnotatedElement對象以後,程序就能夠調用該對象的以下四個個方法來訪問Annotation信息:
註解經過反射獲取。
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}
複製代碼
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}
複製代碼
或者是 getAnnotations() 方法
public Annotation[] getAnnotations() {}
複製代碼
前一種方法返回指定類型的註解,後一種方法返回註解到這個元素上的全部註解。
使用方法
@TestAnnotation()
public class Test {
public static void main(String[] args) {
boolean hasAnnotation = Test.class.isAnnotationPresent(AnnotationTest.class);
if ( hasAnnotation ) {
TestAnnotation testAnnotation = Test.class.getAnnotation(AnnotationTest.class);
System.out.println("id:"+testAnnotation.firstLevelCache());
System.out.println("msg:"+testAnnotation.tableName());
}
}
}
複製代碼
註解是一系列元數據,它提供數據用來解釋程序代碼,可是註解並不是是所解釋的代碼自己的一部分。註解對於代碼的運行效果沒有直接影響。
註解用處主要以下:
編譯器能夠利用註解來探測錯誤和警告信息
軟件工具能夠用來利用註解信息來生成代碼、Html文檔或者作其它相應處理。
某些註解能夠在程序運行的時候接受代碼的提取