Java注释的默认值是否编译为字节码?

我尝试为Java字节码实现几个静态分析。 他们试图计算某个方法是否具有特定属性,例如是工厂方法。 因为这些分析很难测试,所以我决定编写一些Java代码并使用正确的属性直接注释方法。 运行分析后,很容易自动检查计算属性和带注释的属性是否相同。

MyAnnotation:

@Retention(RUNTIME) @Target(METHOD) public @interface FactoryMethodProperty { FactoryMethodKeys value() default FactoryMethodKeys.NonFactoryMethod; } 

示例测试代码:

 public class PublicFactoryMethod { private PublicFactoryMethod(){ // I'm private } @FactoryMethodProperty public static void newInstanceAfterOtherConstructorCall(){ new TransFacoryMethod(); new PublicFactoryMethod(); } @FactoryMethodProperty(FactoryMethodKeys.IsFactoryMethod) public static PublicFactoryMethod newInstance(){ return new PublicFactoryMethod(); } } 

因为我的测试代码中的大多数方法都不是工厂方法,所以我将默认设置为枚举值“FactoryMethodKeys.NonFactoryMethod”。 但是当我没有将枚举值显式传递给注释时,它不会被编译为字节码。

字节码:

  #23 = Utf8 value #24 = Utf8 Lorg/opalj/fpa/test/annotations/FactoryMethodKeys; #25 = Utf8 IsFactoryMethod { public static void newInstanceAfterOtherConstructorCall(); descriptor: ()V flags: ACC_PUBLIC, ACC_STATIC RuntimeVisibleAnnotations: 0: #16() Code: stack=1, locals=0, args_size=0 0: new #17 // class factoryMethodTest/TransFacoryMethod 3: invokespecial #19 // Method factoryMethodTest/TransFacoryMethod."":()V 6: new #1 // class factoryMethodTest/PublicFactoryMethod 9: invokespecial #20 // Method "":()V 12: return LineNumberTable: line 49: 0 line 50: 6 line 51: 12 LocalVariableTable: Start Length Slot Name Signature public static factoryMethodTest.PublicFactoryMethod newInstance(); descriptor: ()LfactoryMethodTest/PublicFactoryMethod; flags: ACC_PUBLIC, ACC_STATIC RuntimeVisibleAnnotations: 0: #16(#23=e#24.#25) Code: stack=2, locals=0, args_size=0 0: new #1 // class factoryMethodTest/PublicFactoryMethod 3: dup 4: invokespecial #20 // Method "":()V 7: areturn LineNumberTable: line 55: 0 LocalVariableTable: Start Length Slot Name Signature } 

我错了什么? 为什么完全忽略默认值?

它不需要在那里。 在运行时,JVM构造可以检索的注释实例。 此实例将使用default值进行初始化,该default值位于注释本身的.class文件中。 这表示为AnnotationDefault属性

AnnotationDefault属性是某些method_info结构(第4.6节)的属性表中的可变长度属性,即表示注释类型元素的属性。 AnnotationDefault属性记录method_info结构表示的元素的默认值。

表示注释类型的元素的每个method_info结构可以包含至多一个AnnotationDefault属性。 Java虚拟机必须使此默认值可用,以便可以通过适当的reflectionAPI应用它

您最终将调用注释实例的value()方法(或您定义的任何其他方法),它将返回该值。

如果您查看注释的字节码,您将在那里看到默认值。 使用javap -c -v并修剪不相关的东西:

 ... ConstantPool: #7 = Utf8 LFactoryMethodKeys #8 = Utf8 NonFactoryMethod ... { public abstract FactoryMethodKeys value(); flags: ACC_PUBLIC, ACC_ABSTRACT AnnotationDefault: default_value: e#7.#8}