Annotation
注解实现
我们知道注解有一个存活时间,有3类,这3类都是有一个Enum实现的 RetentionPolicy
/**
* TestAnnotation retention policy. The constants of this enumerated type
* describe the various policies for retaining annotations. They are used
* in conjunction with the {@link Retention} meta-annotation type to specify
* how long annotations are to be retained.
*
* @author Joshua Bloch
* @since 1.5
*/
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
//编译器可见(也就是可以用于apt)
//不会写入到class字节码里面
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
//写入到class文件里面.但是运行期间不可见
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
//运行期也可以获取
RUNTIME
}
SOURCE & CLASS
这方面的实现笔者实力有限不能进行分析,这得去看javac(java compiler)
不过我们可以验证一下
@Retention(RetentionPolicy.SOURCE)
public @interface MyAnnotation {
byte a() default 0;
short b() default 0;
int c() default 0;
long d() default 0;
double e() default 0;
float f() default 0;
boolean g() default false;
String h() default "";
Class<?> i() default Object.class;
}
@MyAnnotation()
public class TestAnnotation {
public static void main(String[] args) {
System.out.println(Arrays.toString(TestAnnotation.class.getAnnotations()));
}
}
完全没有annotation的标记
修改为@Retention(RetentionPolicy.CLASS)
可以发现代码的注释其实是给的很清楚的,没有骗我们.
RUNTIME
什么是注解?
JVM并没有为注解定义新的类型,所以注解会是什么? 这个嘛看看字节码就知道了
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
byte a() default 0;
short b() default 0;
int c() default 0;
long d() default 0;
double e() default 0;
float f() default 0;
boolean g() default false;
String h() default "";
Class<?> i() default Object.class;
}
分析一下字节码
晴天霹雳有没有? 注解底层在javac的蹂躏下变成了一个interface
对比一下interface
public interface MyInterface {
short a();
int b();
}
差别不大就是annotation多了一个名为java.lang.annotation.Annotation的父类
看看就好了
public interface Annotation {
/**
* Returns true if the specified object represents an annotation
* that is logically equivalent to this one. In other words,
* returns true if the specified object is an instance of the same
* annotation type as this instance, all of whose members are equal
* to the corresponding member of this annotation, as defined below:
* <ul>
* <li>Two corresponding primitive typed members whose values are
* {@code x} and {@code y} are considered equal if {@code x == y},
* unless their type is {@code float} or {@code double}.
*
* <li>Two corresponding {@code float} members whose values
* are {@code x} and {@code y} are considered equal if
* {@code Float.valueOf(x).equals(Float.valueOf(y))}.
* (Unlike the {@code ==} operator, NaN is considered equal
* to itself, and {@code 0.0f} unequal to {@code -0.0f}.)
*
* <li>Two corresponding {@code double} members whose values
* are {@code x} and {@code y} are considered equal if
* {@code Double.valueOf(x).equals(Double.valueOf(y))}.
* (Unlike the {@code ==} operator, NaN is considered equal
* to itself, and {@code 0.0} unequal to {@code -0.0}.)
*
* <li>Two corresponding {@code String}, {@code Class}, enum, or
* annotation typed members whose values are {@code x} and {@code y}
* are considered equal if {@code x.equals(y)}. (Note that this
* definition is recursive for annotation typed members.)
*
* <li>Two corresponding array typed members {@code x} and {@code y}
* are considered equal if {@code Arrays.equals(x, y)}, for the
* appropriate overloading of {@link java.util.Arrays#equals}.
* </ul>
*
* @return true if the specified object represents an annotation
* that is logically equivalent to this one, otherwise false
*/
boolean equals(Object obj);
/**
* Returns the hash code of this annotation, as defined below:
*
* <p>The hash code of an annotation is the sum of the hash codes
* of its members (including those with default values), as defined
* below:
*
* The hash code of an annotation member is (127 times the hash code
* of the member-name as computed by {@link String#hashCode()}) XOR
* the hash code of the member-value, as defined below:
*
* <p>The hash code of a member-value depends on its type:
* <ul>
* <li>The hash code of a primitive value <i>{@code v}</i> is equal to
* <code><i>WrapperType</i>.valueOf(<i>v</i>).hashCode()</code>, where
* <i>{@code WrapperType}</i> is the wrapper type corresponding
* to the primitive type of <i>{@code v}</i> ({@link Byte},
* {@link Character}, {@link Double}, {@link Float}, {@link Integer},
* {@link Long}, {@link Short}, or {@link Boolean}).
*
* <li>The hash code of a string, enum, class, or annotation member-value
I <i>{@code v}</i> is computed as by calling
* <code><i>v</i>.hashCode()</code>. (In the case of annotation
* member values, this is a recursive definition.)
*
* <li>The hash code of an array member-value is computed by calling
* the appropriate overloading of
* {@link java.util.Arrays#hashCode(long[]) Arrays.hashCode}
* on the value. (There is one overloading for each primitive
* type, and one for object reference types.)
* </ul>
*
* @return the hash code of this annotation
*/
int hashCode();
/**
* Returns a string representation of this annotation. The details
* of the representation are implementation-dependent, but the following
* may be regarded as typical:
* <pre>
* @com.acme.util.Name(first=Alfred, middle=E., last=Neuman)
* </pre>
*
* @return a string representation of this annotation
*/
String toString();
/**
* Returns the annotation type of this annotation.
* @return the annotation type of this annotation
*/
Class<? extends Annotation> annotationType();
}
getAnnotations
先看一段代码
@MyAnnotation()
public class TestAnnotation {
public static void main(String[] args) {
System.out.println(Arrays.toString(TestAnnotation.class.getAnnotations()));
}
}
[@MyAnnotation(a=0, b=0, c=0, d=0, e=0.0, f=0.0f, g=false, h="", i=java.lang.Object.class)]
发现问题没?
- 注解是抽象的
- getAnnotations明显拿到的就是实现类他是具体的,怎么做到的?
- 这个实现类是谁帮我们实现的,又是怎么实现的?
透个底
@MyAnnotation()
public class TestAnnotation {
public static void main(String[] args) {
System.out.println(TestAnnotation.class.getAnnotations()[0].getClass().getName());
}
}
com.sun.proxy.$Proxy1
java 注解的底层是依靠jdk动态代理动态生成实现类
详细
首先我们能推断出jdk动态代理肯定是在调用getClass之前生成的, 盲猜getAnnotations生成.
public Annotation[]getAnnotations(){
return AnnotationParser.toArray(annotationData().annotations);
}
private AnnotationData createAnnotationData(int classRedefinedCount){
Map<Class<?extends Annotation>,Annotation>declaredAnnotations=
AnnotationParser.parseAnnotations(getRawAnnotations(),getConstantPool(),this);
Class<?> superClass=getSuperclass();
Map<Class<?extends Annotation>,Annotation>annotations=null;
//......
//parse...
//......
return new AnnotationData(annotations,declaredAnnotations,classRedefinedCount);
}
public static Map<Class<?extends Annotation>,Annotation>parseAnnotations(
byte[]rawAnnotations,
ConstantPool constPool,
Class<?> container){
if(rawAnnotations==null)
return Collections.emptyMap();
try{
//继续解析
return parseAnnotations2(rawAnnotations,constPool,container,null);
}catch(BufferUnderflowException e){
throw new AnnotationFormatError("Unexpected end of annotations.");
}catch(IllegalArgumentException e){
// Type mismatch in constant pool
throw new AnnotationFormatError(e);
}
}
private static Map<Class<?extends Annotation>,Annotation>parseAnnotations2(
byte[]rawAnnotations,
ConstantPool constPool,
Class<?> container,
Class<?extends Annotation>[]selectAnnotationClasses){
Map<Class<?extends Annotation>,Annotation>result=
new LinkedHashMap<Class<?extends Annotation>,Annotation>();
ByteBuffer buf=ByteBuffer.wrap(rawAnnotations);
int numAnnotations=buf.getShort()&0xFFFF;
for(int i=0;i<numAnnotations; i++){
//继续parse
Annotation a=parseAnnotation2(buf,constPool,container,false,selectAnnotationClasses);
if(a!=null){
Class<?extends Annotation> klass=a.annotationType();
if(AnnotationType.getInstance(klass).retention()==RetentionPolicy.RUNTIME&&
result.put(klass,a)!=null){
throw new AnnotationFormatError(
"Duplicate annotation for class: "+klass+": "+a);
}
}
}
return result;
}
static Annotation parseAnnotation(ByteBuffer buf,
ConstantPool constPool,
Class<?> container,
boolean exceptionOnMissingAnnotationClass){
return parseAnnotation2(buf,constPool,container,exceptionOnMissingAnnotationClass,null);
}
@SuppressWarnings("unchecked")
private static Annotation parseAnnotation2(ByteBuffer buf,
ConstantPool constPool,
Class<?> container,
boolean exceptionOnMissingAnnotationClass,
Class<?extends Annotation>[]selectAnnotationClasses){
//......
//海量的解析
return annotationForMap(annotationClass,memberValues);
}
public static Annotation annotationForMap(final Class<?extends Annotation> type,
final Map<String, Object> memberValues)
{
return AccessController.doPrivileged(new PrivilegedAction<Annotation>(){
public Annotation run(){
//露出尾巴了
return(Annotation)Proxy.newProxyInstance(
type.getClassLoader(),new Class<?>[]{type},
new AnnotationInvocationHandler(type,memberValues));
}});
}
后续的invoke就是由AnnotationInvocationHandler进行代理
至于生成的字节码嘛,开启属性即可
System.setProperty("jdk.proxy.ProxyGenerator.saveGeneratedFiles","true");
可以发现这个代理类代理的接口就是我们的注解
public final class $Proxy1 extends Proxy implements MyAnnotation {
private static Method m1;
private static Method m5;
private static Method m9;
private static Method m8;
private static Method m6;
private static Method m2;
private static Method m7;
private static Method m10;
private static Method m12;
private static Method m4;
private static Method m11;
private static Method m3;
private static Method m0;
public $Proxy1(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean) super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final short b() throws {
try {
return (Short) super.h.invoke(this, m5, (Object[]) null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final byte a() throws {
try {
return (Byte) super.h.invoke(this, m9, (Object[]) null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final long d() throws {
try {
return (Long) super.h.invoke(this, m8, (Object[]) null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int c() throws {
try {
return (Integer) super.h.invoke(this, m6, (Object[]) null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String) super.h.invoke(this, m2, (Object[]) null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final float f() throws {
try {
return (Float) super.h.invoke(this, m7, (Object[]) null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final double e() throws {
try {
return (Double) super.h.invoke(this, m10, (Object[]) null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final Class annotationType() throws {
try {
return (Class) super.h.invoke(this, m12, (Object[]) null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String h() throws {
try {
return (String) super.h.invoke(this, m4, (Object[]) null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final boolean g() throws {
try {
return (Boolean) super.h.invoke(this, m11, (Object[]) null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final Class i() throws {
try {
return (Class) super.h.invoke(this, m3, (Object[]) null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer) super.h.invoke(this, m0, (Object[]) null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m5 = Class.forName("MyAnnotation").getMethod("b");
m9 = Class.forName("MyAnnotation").getMethod("a");
m8 = Class.forName("MyAnnotation").getMethod("d");
m6 = Class.forName("MyAnnotation").getMethod("c");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m7 = Class.forName("MyAnnotation").getMethod("f");
m10 = Class.forName("MyAnnotation").getMethod("e");
m12 = Class.forName("MyAnnotation").getMethod("annotationType");
m4 = Class.forName("MyAnnotation").getMethod("h");
m11 = Class.forName("MyAnnotation").getMethod("g");
m3 = Class.forName("MyAnnotation").getMethod("i");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
小结
- 注解在class字节码层面上就是一个extends Annotation的接口
- 注解source,class时期是依靠的java compiler编译期实现
- 注解的runtime数据的获取是依靠的jdk动态代理动态生成实现类