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

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