注解
{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.pngjavap -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类,而成员属性和方法实现相关都是在编译完成后就已经成型的,枚举类型的成员变量都是通过静态代码块声明的。
网友评论