注解Annotation
概念相關(guān)
JDK5開始,java增加了對元數(shù)據(jù)(MetaData)的支持砸王,也就是Annotation赤赊。
Annotation其實就是代碼里的特殊標(biāo)記,這些編輯可以在編譯洽沟、類加載囤锉、運行的時候被讀取坦弟,并執(zhí)行相應(yīng)的處理」俚兀可以實現(xiàn)不改變原有邏輯的情況下酿傍,源代碼中嵌入補充信息。
它是一種程序元素(類区丑、方法、成員變量等)的元數(shù)據(jù),不會影響程序邏輯沧侥。
注解分類
根據(jù)注解參數(shù)的個數(shù)分類
- 標(biāo)記注解:一個沒有成員定的以的Annotation可霎;這種Annotation類型僅適用自身的存在與否來為我們提供信息。
- 單值注解:只存在 value = "xxx"宴杀;通常@Annotation("xxx");value=可以省略
- 完整注解
根據(jù)注解適用方法和用途分類
- JDK內(nèi)置系統(tǒng)注解
- 元注解:標(biāo)記其它注解的注解
- 自定義注解
JDK常用的注解
@Override : 重寫方法
@Deprecated : 表示某個程序元素(類癣朗、方法等)已經(jīng)過時
@SuppressWarnings : 抑制編譯器警告
-
@SafeVarargs : 堆污染警告(java7出現(xiàn))
堆污染:把一個不帶泛型的對象賦給一個帶泛型的變量
List list = new ArrayList<Integer>(); list.add(20); List<String> ls = list; System.out.println(ls.get(0));
-
@Functionallnterface : 函數(shù)式接口
接口中只有一個抽象方法,該接口就是函數(shù)式接口旺罢,@FunctionalInterface 就是用來執(zhí)行某個接口必須是函數(shù)式接口旷余。
JDK元Annotation
5個元Annotation 用于修飾其它Annotation的定義
-
@Retention : 用于執(zhí)行被修飾的Annotation可以保留多長時間
value的值:
? RetentionPolicy.CLASS : 編譯器把Annotation記錄在class中,當(dāng)運行java程序時扁达,jvm獲取不到正卧,默認(rèn)值
? RetentionPolicy.RUNTIME:編譯器把Annotation記錄在class中,當(dāng)運行java程序時跪解,jvm可以獲取到Annotation信息炉旷,程序可以通過反射獲取Annotation信息
? RetentionPolicy.SOURCE:編譯器把Annotation記錄在源碼中,class中丟失該Annotation
@Retention(value=RetentionPolicy.RUNTIME) public @interface Test{}
說明:如果使用注解只為value成員變量指定值時叉讥,可以括號內(nèi)直接指定value,如:
@Retention(RetentionPolicy.RUNTIME) public @interface Test{}
-
@Target
@Target 只能修飾一個Annotation窘行,用于指定被修飾的Annotation能用于修飾在什么地方
value 說明 ElementType.ANNOTATION_TYPE 只能修飾Annotation ElementType.CONSTRUCTOR 構(gòu)造器 ElementType.FIELD 成員變量 ElementType.LOCAL_VARIABLE 局部變量 ElementType.METHOD 方法 ElementType.PACKAGE 包 ElementType.PARAMETER 參數(shù) ElementType.TYPE 類、接口图仓、枚舉 -
@Documented
用于指定被@Documented修飾的annotation修飾的類被javadoc工具提取成文檔
-
@Inherited
用于指定被@Inherited修飾的annotation修飾的類罐盔,具有繼承性;如類A使用了@xxx (@xxx被@Inherited修飾)救崔,那么繼承類A的子類a會自動被@xxx修飾(無需顯示手動寫出)
自定義注解
格式:
public @interface AnnotationName { ... }
說明:
使用@interface自定義注解時惶看,自動繼承了java.lang.annotation.Annotation接口,由編譯程序自動完成的帚豪。在定義注解時候碳竟,不能繼承其它的注解或者接口。
注解支持的數(shù)據(jù)類型
- 基本類型(不支持包裝類型)
- String類型
- Class類型
- enum類型
- Annotation類型
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationDemo {
int value() default 0;
String name() default "";
}
注解的運行原理
注解本質(zhì)是一個繼承了Annotation的特殊接口狸臣,其具體的實現(xiàn)類是java運行時生成的動態(tài)代理類(Debug是莹桅,可以看到動態(tài)代理對象$Proxy1,通過代理對象調(diào)用自定義注解(接口)的方法烛亦,會最終調(diào)用AnnotationInvocationHandler
的invoke
方法诈泼。該方法會從memberValues
這個Map 中索引出對應(yīng)的值。而memberValues
的來源是Java 常量池)煤禽。通過反射獲取注解相關(guān)信息铐达。
注解處理類(AnnotatedElement;也叫注解處理器)檬果,獲取注解信息瓮孙。
Annotation接口唐断,代表注解的注解,是所有注解的父接口
AnnotatedElement接口杭抠,代表程序中可以接受注解的程序元素脸甘;該接口也叫注解處理器;如圖:
-
<T extends Annotation> T getAnnotation(Class<T> annotationClass)
返回程序元素上存在的指定類型的注解偏灿,若不存在丹诀,則返回null
-
Annotation[] getAnnotations()
返回該程序元素上存在的所有注解
-
boolean is AnnotationPresent(Class<?extends Annotation> annotationClass)
判斷程序元素上是否包含指定類型的注解
-
Annotation[] getDeclaredAnnotations()
返回直接存在于此元素上的所有注解(忽略繼承的注解)
獲取注解的過程;也就是上述五個繼承類中(注解處理器)翁垂,getAnnotations 的過程:
客戶端代碼:
Field name = client.getClass().getDeclaredField("name");
AnnotationDemo annotation = name.getAnnotation(AnnotationDemo.class);
Field.java
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
Objects.requireNonNull(annotationClass);
return annotationClass.cast(declaredAnnotations().get(annotationClass));
}
private synchronized Map<Class<? extends Annotation>, Annotation> declaredAnnotations() {
if (declaredAnnotations == null) {
Field root = this.root;
if (root != null) {
declaredAnnotations = root.declaredAnnotations();
} else {
declaredAnnotations = AnnotationParser.parseAnnotations(
annotations,
sun.misc.SharedSecrets.getJavaLangAccess().getConstantPool(getDeclaringClass()),
getDeclaringClass());
}
}
return declaredAnnotations;
AnnotationParser.class
public static Map<Class<? extends Annotation>, Annotation> parseAnnotations(byte[] var0, ConstantPool var1, Class<?> var2) {
if (var0 == null) {
return Collections.emptyMap();
} else {
try {
return parseAnnotations2(var0, var1, var2, (Class[])null);
} catch (BufferUnderflowException var4) {
throw new AnnotationFormatError("Unexpected end of annotations.");
} catch (IllegalArgumentException var5) {
throw new AnnotationFormatError(var5);
}
}
}
private static Map<Class<? extends Annotation>, Annotation> parseAnnotations2(byte[] var0, ConstantPool var1, Class<?> var2, Class<? extends Annotation>[] var3) {
LinkedHashMap var4 = new LinkedHashMap();
ByteBuffer var5 = ByteBuffer.wrap(var0);
int var6 = var5.getShort() & '\uffff';
for(int var7 = 0; var7 < var6; ++var7) {
Annotation var8 = parseAnnotation2(var5, var1, var2, false, var3);
if (var8 != null) {
Class var9 = var8.annotationType();
if (AnnotationType.getInstance(var9).retention() == RetentionPolicy.RUNTIME && var4.put(var9, var8) != null) {
throw new AnnotationFormatError("Duplicate annotation for class: " + var9 + ": " + var8);
}
}
}
return var4;
}
private static Annotation parseAnnotation2(ByteBuffer var0, ConstantPool var1, Class<?> var2, boolean var3, Class<? extends Annotation>[] var4) {
int var5 = var0.getShort() & '\uffff';
Class var6 = null;
String var7 = "[unknown]";
try {
try {
var7 = var1.getUTF8At(var5);
var6 = parseSig(var7, var2);
} catch (IllegalArgumentException var18) {
var6 = var1.getClassAt(var5);
}
} catch (NoClassDefFoundError var19) {
if (var3) {
throw new TypeNotPresentException(var7, var19);
}
skipAnnotation(var0, false);
return null;
} catch (TypeNotPresentException var20) {
if (var3) {
throw var20;
}
skipAnnotation(var0, false);
return null;
}
if (var4 != null && !contains(var4, var6)) {
skipAnnotation(var0, false);
return null;
} else {
AnnotationType var8 = null;
try {
var8 = AnnotationType.getInstance(var6);
} catch (IllegalArgumentException var17) {
skipAnnotation(var0, false);
return null;
}
Map var9 = var8.memberTypes();
LinkedHashMap var10 = new LinkedHashMap(var8.memberDefaults());
int var11 = var0.getShort() & '\uffff';
for(int var12 = 0; var12 < var11; ++var12) {
int var13 = var0.getShort() & '\uffff';
String var14 = var1.getUTF8At(var13);
Class var15 = (Class)var9.get(var14);
if (var15 == null) {
skipMemberValue(var0);
} else {
Object var16 = parseMemberValue(var15, var0, var1, var2);
if (var16 instanceof AnnotationTypeMismatchExceptionProxy) {
((AnnotationTypeMismatchExceptionProxy)var16).setMember((Method)var8.members().get(var14));
}
var10.put(var14, var16);
}
}
return annotationForMap(var6, var10);
}
}
public static Annotation annotationForMap(final Class<? extends Annotation> var0, final Map<String, Object> var1) {
return (Annotation)AccessController.doPrivileged(new PrivilegedAction<Annotation>() {
public Annotation run() {
//該句是重點铆遭;返回動態(tài)代理對象
return (Annotation)Proxy.newProxyInstance(var0.getClassLoader(), new Class[]{var0}, new AnnotationInvocationHandler(var0, var1));
}
});
}
class AnnotationInvocationHandler implements InvocationHandler, Serializable {
private static final long serialVersionUID = 6182022883658399397L;
private final Class<? extends Annotation> type;
//該句是重點:對象池
private final Map<String, Object> memberValues;
private transient volatile Method[] memberMethods = null;
AnnotationInvocationHandler(Class<? extends Annotation> var1, Map<String, Object> var2) {
Class[] var3 = var1.getInterfaces();
if (var1.isAnnotation() && var3.length == 1 && var3[0] == Annotation.class) {
this.type = var1;
this.memberValues = var2;
} else {
throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type.");
}
}
public Object invoke(Object var1, Method var2, Object[] var3) {
}
}