一、前言
本文分析注解體系的主要目的有如下三點:
- 個人的知識體系的梳理,希望能把書由薄讀厚,再由厚讀??;
- 為后續(xù)博文,仿ButterKnife框架的內(nèi)容鋪墊;
- ORM類型框架中大量使用到了注解的內(nèi)容,明確注解意義及使用方法,能夠打通學(xué)習(xí)ORM類型框架的任督二脈。
進入正題:
- 用專業(yè)名詞解釋專業(yè)名詞的注解說明版本如下:
- 個人認為這樣去理解適合于有經(jīng)驗的開發(fā)同學(xué)。
從JDK5開始,Java增加了對元數(shù)據(jù)(MetaData)的支持,也就是Annotation(即注解),這里介紹的注解,其實是代碼里的特殊標記,這些標記可以在編譯、類加載。運行時被讀取,并執(zhí)行相應(yīng)的處理。通過使用注解,程序開發(fā)人員可以在不改變原有邏輯的情況下,在源文件中嵌入一些補充的信息。代碼分析工具、開發(fā)工具和部署工具可以通過改變這些補充信息進行驗證或者進行部署。 ———《瘋狂Java講義》

二、注解體系
1、注解概述
注解提供了一種為程序元素設(shè)置元數(shù)據(jù)的方法,從某些方面來看,注解就像修飾符一樣,可以用于修飾包、類、構(gòu)造器、方法、成員變量、參數(shù)、局部變量的聲明,這些信息被儲存在注解的“name=value”對中。
注解能被用來為程序元素(類、方法、成員變量)設(shè)置元數(shù)據(jù)。值得指出的是,注解不影響程序代碼的執(zhí)行,無論添加、刪除注解,代碼都始終如一的執(zhí)行。如果希望讓程序中的注解在運行時起一定的作用,只有通過某種配套的工具對注解中的信息進行訪問和處理,訪問和處理注解的工具統(tǒng)稱為APT(Annotation Processing Tool)。
1.1 元數(shù)據(jù)(metadata)
元數(shù)據(jù)(metadata):就是關(guān)于數(shù)據(jù)的數(shù)據(jù)。
- 示例:
①表格中呈現(xiàn)的是數(shù)據(jù),而表格還會有額外的數(shù)據(jù)來說明表格的作用,這個就是表格的元數(shù)據(jù)。
②數(shù)據(jù)庫中的表存放了數(shù)據(jù),但表還需要有表的定義、字段的定義等,這個就是數(shù)據(jù)庫表的元數(shù)據(jù)。
③XML文件可以存放數(shù)據(jù)。但xml文件的每個標簽還需要有相應(yīng)的描述,這些描述就是XML標簽的元數(shù)據(jù)。 - 元數(shù)據(jù)可以用于創(chuàng)建文檔,跟蹤代碼中的依賴性,甚至執(zhí)行基本編譯時檢查。
1.2 什么是Annotation
- JDK5.0通過名為Annotation(注解)的新功能將一個更通用的元數(shù)據(jù)工具合并到核心 Java 語言中。
- 注解是可以添加到代碼中的修飾符,對程序代碼做出一些說明和解釋??梢杂糜诎暶?、類聲明、構(gòu)造方法、方法、字段、參數(shù)和變量。
這樣就將程序的元素和元數(shù)據(jù)聯(lián)系起來。編譯器就可以將元數(shù)據(jù)存儲在Class文件中。之后虛擬機和其它對象可以根據(jù)這些元數(shù)據(jù)來決定如何使用這些程序元素或改變它們的行為。 - JDK5.0包含了內(nèi)置注解,還支持編寫定制注解。
1.3 注解基本知識
- 注解采用“@”標記形式 ,后面跟注解類型名稱。通過(name=value)向注解提供參數(shù)數(shù)據(jù)。每次使用這類表示法時,就是在生成注解。
注解類型和注解的區(qū)別:注解類型類似于類,注解類似于該類的實例
2、內(nèi)置注解類型
2.1 內(nèi)置注解類型—Override
- Override 指明被注解的方法必須是重寫超類中的方法。僅能用于方法之上。
編譯器在編譯源代碼時會檢查用@Override標注的方法是否有重寫父類的方法。
舉例如下:
public class InternalAnnotationTest {
@Override
public String toString() {
return super.toString() + " [Override toString]";
}
public static void main(String[] args) {
TestAnnotation test = new TestAnnotation();
System.out.println(test);
}
}
2.2 內(nèi)置注解類型—Deprecated
- Deprecated 指明被注解的方法為過時的方法,不建議使用了。能用于方法之上。
當編譯調(diào)用到被標注為Deprecated的方法的類時,編譯器會產(chǎn)生警告。
舉例如下:
public class InternalAnnotationTest {
…
@Deprecated
public void test(){
System.out.println("[Deprecated Annotation]");
}
}
2.3 內(nèi)置注解類型—SuppressWarnings
- SuppressWarnings 指明被注解的方法在編譯時如果有警告信息,就阻止警告??煞胖萌魏挝恢?。
- 它有一個必需屬性:value,是String[]類型的,指定取消顯示的警告集。警告類型如下:
| 類型 | 作用 |
|---|---|
| unused | 未被使用的警告 |
| deprecation | 使用了不贊成使用的類或方法時的警告 |
| unchecked | 執(zhí)行了未檢查的轉(zhuǎn)換時的警告 |
| rawtypes | 沒有用泛型 (Generics) 的警告 |
| fallthrough | 當 Switch 程序塊直接通往下一種情況而沒有 Break 時的警告。 |
| path | 在類路徑、源文件路徑等中有不存在的路徑時的警告。 |
| serial | 當在可序列化的類上缺少 serialVersionUID 定義時的警告。 |
| finally | 任何 finally 子句不能正常完成時的警告。 |
| all | 關(guān)于以上所有情況的警告。 |
舉例如下:
public class InternalAnnotationTest {
@SuppressWarnings(value={"unchecked", "deprecation"})
public void test() {
Map map = new HashMap();
map.put("name", "Alex");
System.out.println(map);
}
}
3、自定義注解類型
格式如下:
[訪問修飾符] @interface 注解類型名 {
數(shù)據(jù)類型 屬性名() [default 默認值];//定義屬性
}
舉例如下:
public @interface AlexDebug{
}
public @interface AlexAnnotation{
String value();
}
public @interfacle AlexType{
int age() default 18;
}
4、元注解
元注解:對注解的注解
- 為注解類型提供某種元數(shù)據(jù),使用系統(tǒng)預(yù)定義的元注解可以對我們的注解進行注解。
結(jié)合元注解,我們可以對自定義注解類型進行相當大程度的內(nèi)容補充說明。
Java的API為我們提供的元注解如下:
4.1 @Target
指定此注解的適用時機
- 在定義注解類型時,使用java.lang.annotation.Target可以定義其適用的時機。
在定義時要指定為java.lang.annation.ElementType的枚舉值之一:
package java.lang.annotation;
public enum ElementType{
TYPE, //適用于 類,接口,枚舉
FIELD, //適用于 成員字段
METHOD, //適用于 方法
PARAMETER, //適用于 方法的參數(shù)
CONSTRUCTOR, //適用于 構(gòu)造方法
LOCAL_VARIABLE, //適用于 局部變量
ANNOTATION_TYPE, //適用于 注解類型
PACKAGE //適用于 包
}
舉例如下:
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
//聲明注解適用于方法
@Target({ElementType.METHOD})
public @interface AlexAnnotation {
}
4.2 @Retention
- 使用java.lang.annotation.Retention用來告訴編譯器如何處理當前注解。
在使用Retention類型時,需要提供java.lang.annotation.RetentionPolicy的枚舉類型,它的定義如下:
package java.lang.annotation;
public enum RetentionPolicy {
SOURCE, //編譯器處理完后,并不將它保留到編譯后的類文件中
CLASS, //編譯器將注解保留在編譯后的類文件中,但是在運行時忽略它
RUNTIME //編譯器將注解保留在編譯后的類文件中,并在第一次加載類時讀取它
}
內(nèi)置注解中的Override、SuppressWarnings的RetentionPolicy為SOURCE,而Deprecated為RUNTIME
4.3 @Documented
- 在默認情況下,注解不包括在Javadoc 中,用java.lang.annatation.Documented可以使此注解加入到Javadoc中。
- 定義為Documented的注解必須要設(shè)置Retention的值為RetentionPolicy.RUNTIME。
舉例如下:
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface DocAnnotation {
}
4.5 @Inherited
- 定義的注解類型使用于程序代碼上后,默認父類中的注解并不會繼承至子類中。
如果想讓父類中的注解被繼承到子類中,可以在定義注解類型時加上java.lang.annotation.Inherited類型的注解。
舉例如下:
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Alex{
String name();
int value();
}
@Alex(name="John Snow",age=32)
public class Parent{}
class SubClass extends Parent{}
4.6 @Repeatable
- 意味著注解的值可以同時取多個
@Repeatable是Java1.8加進來的新注解,同樣這里我們舉個例子:
@interface Persons {
Person[] value();
}
@Repeatable(Persons.class)
@interface HumanBeing{
String role default "coder";
}
@Person(role="PM")
@Person(role="Teacher")
@Person(role="Reader")
public class Alex{
}
三、結(jié)語
1、一個技術(shù)開發(fā)人員老去的標志,絕不是老成穩(wěn)重、沉默寡言,而是不肯再嘗試,不肯再容許自己置身不熟悉的境地。
2、一個技術(shù)開發(fā)人員開始廢掉的跡象之二,便是沉溺于短期快感之中,不再做長期投入。不再深入研究底層內(nèi)容。在這里,我對注解相關(guān)的知識體系進行梳理,后續(xù)會推出更多的內(nèi)容和大家分享。
3、一個技術(shù)開發(fā)人員開始廢掉的跡象之三,是淪為抵觸的情緒的奴隸。遇到新技術(shù)畏手畏腳,遇困難而退縮。
希望我們一起努力,加油!