Java注解是如何玩转的,面试官和我聊了半个小时

面试官:自定义的Java注解是如何生效的? 

小白:自定义注解后,需要定义这个注解的注解解析及处理器,在这个注解解析及处理器的内部,通过反射使用Class、Method、Field对象的getAnnotation()方法可以获取各自位置上的注解信息,进而完成注解所需要的行为,例如给属性赋值、查找依赖的对象实例等。

面试官:你说的是运行时的自定义注解解析处理,如果要自定义一个编译期生效的注解,如何实现? 

小白:自定义注解的生命周期在编译期的,声明这个注解时@Retention的值为RetentionPolicy.CLASS,需要明确的是此时注解信息保留在源文件和字节码文件中,在JVM加载class文件后,注解信息不会存在内存中。声明一个类,这个类继承javax.annotation.processing.AbstractProcessor抽象类,然后重写这个抽象类的process方法,在这个方法中完成注解所需要的行为。

面试官:你刚刚说的这种方式的实现原理是什么? 

小白:在使用javac编译源代码的时候,编译器会自动查找所有继承自AbstractProcessor的类,然后调用它们的process方法,通过RoundEnvironment#getElementsAnnotatedWith方法可以获取所有标注某注解的元素,进而执行相关的行为动作。

面试官:有如下的一个自定义注解,在使用这个注解的时候,它的value值是存在哪的?

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
     String value() default "";
}

小白:使用javap -verbose命令查看这个注解的class文件,发现这个注解被编译成了接口,并且继承了java.lang.annotation.Annotation接口,接口是不能直接实例化使用的,当在代码中使用这个注解,并使用getAnnotation方法获取注解信息时,JVM通过动态代理的方式生成一个实现了Test接口的代理对象实例,然后对该实例的属性赋值,value值就存在这个代理对象实例中。

Classfile /Test/bin/Test.class
    Last modified 2020-3-23; size 423 bytes
  MD5 checksum be9fb08ef7e5f2c4a1bca7d6f856cfa5
  Compiled from "Test.java"
public interface Test extends java.lang.annotation.Annotation
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
Constant pool:
   #1 = Class              #2             // Test
   #2 = Utf8               Test
   #3 = Class              #4             // java/lang/Object
   #4 = Utf8               java/lang/Object
   #5 = Class              #6             // java/lang/annotation/Annotation
   #6 = Utf8               java/lang/annotation/Annotation
   #7 = Utf8               value
   #8 = Utf8               ()Ljava/lang/String;
   #9 = Utf8               AnnotationDefault
  #10 = Utf8               T
  #11 = Utf8               SourceFile
  #12 = Utf8               Test.java
  #13 = Utf8               RuntimeVisibleAnnotations
  #14 = Utf8               Ljava/lang/annotation/Target;
  #15 = Utf8               Ljava/lang/annotation/ElementType;
  #16 = Utf8               TYPE
  #17 = Utf8               Ljava/lang/annotation/Retention;
  #18 = Utf8               Ljava/lang/annotation/RetentionPolicy;
  #19 = Utf8               RUNTIME
{
  public abstract java.lang.String value();
    descriptor: ()Ljava/lang/String;
    flags: ACC_PUBLIC, ACC_ABSTRACT
    AnnotationDefault:
      default_value: s#10}
SourceFile: "Test.java"
RuntimeVisibleAnnotations:
  0: #14(#7=[e#15.#16])
  1: #17(#7=e#18.#19)

面试官:有没有看过这部分的实现源代码? 

小白:看过,

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值