java 注解枚举的底层实现

2020-11-09  本文已影响0人  hehehehe
注解
{InterfaceModifier} @ interface Identifier AnnotationTypeBody

接口修饰符 @ interface 注解标识符 注解类型的内容

注解类型声明中的标识符指定了注解类型的名称。
如果注解类型与它的任何封闭类或接口具有相同的简单名称,则编译时会出现错误。
每个注解类型的直接父接口都是java.lang.annotation.Annotation。

javap -c -v D:\Projects\rxjava-seed\target\classes\club\Counter.class

Classfile /D:/Projects/rxjava-seed/target/classes/club/throwable/annotation/Counter.class
  Last modified 2018-10-6; size 487 bytes
  MD5 checksum 83cee23f426e5b51a096281068d8b555
  Compiled from "Counter.java"
public interface club.throwable.annotation.Counter extends java.lang.annotation.Annotation
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
Constant pool:
   #1 = Class              #19            // club/throwable/annotation/Counter
   #2 = Class              #20            // java/lang/Object
   #3 = Class              #21            // java/lang/annotation/Annotation
   #4 = Utf8               count
   #5 = Utf8               ()I
   #6 = Utf8               AnnotationDefault
   #7 = Integer            0
   #8 = Utf8               SourceFile
   #9 = Utf8               Counter.java
  #10 = Utf8               RuntimeVisibleAnnotations
  #11 = Utf8               Ljava/lang/annotation/Retention;
  #12 = Utf8               value
  #13 = Utf8               Ljava/lang/annotation/RetentionPolicy;
  #14 = Utf8               RUNTIME
  #15 = Utf8               Ljava/lang/annotation/Documented;
  #16 = Utf8               Ljava/lang/annotation/Target;
  #17 = Utf8               Ljava/lang/annotation/ElementType;
  #18 = Utf8               TYPE
  #19 = Utf8               club/throwable/annotation/Counter
  #20 = Utf8               java/lang/Object
  #21 = Utf8               java/lang/annotation/Annotation
{
  public abstract int count();
    descriptor: ()I
    flags: ACC_PUBLIC, ACC_ABSTRACT
    AnnotationDefault:
      default_value: I#7}
SourceFile: "Counter.java"
RuntimeVisibleAnnotations:
  0: #11(#12=e#13.#14)
  1: #15()
  2: #16(#12=[e#17.#18])

既然注解最后转化为一个接口,注解中定义的注解成员属性会转化为抽象方法,那么最后这些注解成员属性怎么进行赋值的呢?答案就是:为注解对应的接口生成一个实现该接口的动态代理类。直接点说就是:Java通过动态代理的方式生成了一个实现了"注解对应接口"的实例,该代理类实例实现了"注解成员属性对应的方法",这个步骤类似于"注解成员属性"的赋值过程,这样子就可以在程序运行的时候通过反射获取到注解的成员属性(这里注解必须是运行时可见的,也就是使用了@Retention(RetentionPolicy.RUNTIME),另外需要理解JDK原生动态代理和反射相关内容)。

枚举
image.png

javap -c -v D:\Projects\rxjava-seed\target\classes\club\enumeration\PhoneOsEnum.class

枚举的声明格式是:{ClassModifier} enum Identifier [Superinterfaces] EnumBody,
ClassModifier是修饰符,Identifier是枚举的名称可以类比为类名,枚举类型可以实现接口。
枚举类型不能使用abstract或者final修饰,否则会产生编译错误。
枚举类型的直接超类是java.lang.Enum。
枚举类型除了枚举常量定义之外没有其他实例,也就是枚举类型不能实例化。
枚举类型禁用反射操作进行实例化(这个特性就是Effetive Java中推荐使用枚举实现单例的原因)。

JDK中枚举的底层实现就是使用了enum关键字声明的枚举类编译后最终会变成public final修饰同时实现了泛型接口java.lang.Enum并且指定泛型参数为自身的普通Java类,而成员属性和方法实现相关都是在编译完成后就已经成型的,枚举类型的成员变量都是通过静态代码块声明的。

上一篇下一篇

猜你喜欢

热点阅读