Java之道系列:Annotation实现机制

今天来研究研究Java的注解是如何实现的。最简单的,先来看看注解的class文件是什么样的。

class文件支持

直接看栗子,

import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface Ann0tation {String attr();}

javap一下,

Classfile /home/blues/Projects/just4fun/out/production/just4fun/me/kisimple/just4fun/Ann0tation.class Last modified Feb 10, 2015; size 432 bytes MD5 checksum d87c1a02d469944f093b8a1815add76f Compiled from “Ann0tation.java”public interface meSourceFile: “Ann0tation.java” RuntimeVisibleAnnotations:0: #9(#10:[e#11.#12])1: #13(#10:e#14.#15) minor version: 0 major version: 51 flags: ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATIONConstant pool: { public abstract java.lang.String attr();flags: ACC_PUBLIC, ACC_ABSTRACT}

可以看到,所有的注解都继承了java.lang.annotation.Annotation这个接口,

..lang.annotation.Annotation

接下来看下使用了注解后的class文件,

{@Ann0tation(attr = “hello main.”)(String[] args) throws Exception {Method mm = Main.class.getMethod(“main”, String[].class);for (Annotation anno : mm.getDeclaredAnnotations()) {if(anno instanceof Ann0tation) {System.out.println(((Ann0tation)anno).attr());}}}} main(java.lang.String[]) throws java.lang.Exception;flags: ACC_PUBLIC, ACC_STATICCode:: ldc#3;// String main5: iconst_16: anewarray#4;// class java/lang/Class9: dup10: iconst_011: ldc_w#5;// class “[Ljava/lang/String;”14: aastore15: invokevirtual #6;// Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;18: astore_119: aload_120: invokevirtual #7;// Method java/lang/reflect/Method.getDeclaredAnnotations:()[Ljava/lang/annotation/Annotation;23: astore_224: aload_225: arraylength26: istore_327: iconst_0: iload_333: if_icmpge7236: aload_237: iload439: aaload: instanceof : getstatic: checkcast: invokevirtual : : returnLineNumberTable:line 13: 0line 14: 19line 15: 42line 16: 50line 14: 66line 19: 72LocalVariableTable:Start Length Slot Name Signatureanno Ljava/lang/annotation/Annotation;arr$ [Ljava/lang/annotation/Annotation;len$ Ii$ Iargs [Ljava/lang/String;mm Ljava/lang/reflect/Method;StackMapTable: number_of_entries = 3frame_type = 255 /* full_frame */offset_delta = 30locals = [ , int, int ]stack = []frame_type = 35 /* same */frame_type = 248 /* chop */offset_delta = 5Exceptions:throws java.lang.ExceptionRuntimeVisibleAnnotations:0: #39(#40:s#41)

会发现最后多出来了RuntimeVisibleAnnotations这么一个属性,而它的值就是我们给main方法添加的注解,

其实在上面Ann0tation的class文件里面就有这个属性了,因为Ann0tation使用了Target跟Retention注解。关于该属性可以参考。 这么看下来,注解的定义与普通的接口其实并没有什么两样,只是编译器会在使用了注解的地方去添加一个RuntimeVisibleAnnotations属性,保存下我们添加的注解。这样即使在运行时,我们还是可以通过class文件来拿到我们添加的注解。

反射注解实例

既然注解只是个普通的接口,,那么当我们使用反射去拿到的注解的实例(看上面的栗子)又是个什么鬼?看看源码就知道了。 上面我们所调用的,最后是会去调用 ,

/*** Parses the annotations described by the specified byte array.* resolving constant references in the specified constant pool.* The array must contain an array of annotations as described* in the RuntimeVisibleAnnotations_attribute:** u2 num_annotations;* annotation annotations[num_annotations];** @throws AnnotationFormatError if an annotation is found to be*malformed.*/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) {AnnotationFormatError(e);}}与其在那里苦苦挣扎,碍于面子硬撑,倒不如微笑着面对,

Java之道系列:Annotation实现机制

相关文章:

你感兴趣的文章:

标签云: