是Java注释';s编译成字节码的默认值?

是Java注释';s编译成字节码的默认值?,java,annotations,java-8,bytecode,Java,Annotations,Java 8,Bytecode,我尝试为Java字节码实现几个静态分析。他们试图计算某个方法是否具有特定属性,例如,是否为工厂方法。因为这些分析很难测试,所以我决定编写一些Java代码,并直接用正确的属性对方法进行注释。运行分析后,很容易自动检查计算属性和注释属性是否相同 MyAnnotation: @保留(运行时) @目标(方法) public@interface FactoryMethodProperty{ FactoryMethodKeys值()默认FactoryMethodKeys.NonFactoryMethod;

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

MyAnnotation:

@保留(运行时)
@目标(方法)
public@interface FactoryMethodProperty{
FactoryMethodKeys值()默认FactoryMethodKeys.NonFactoryMethod;
}
示例测试代码:

公共类PublicFactoryMethod{
私有PublicFactoryMethod(){
//我是二等兵
}
@FactoryMethodProperty
public static void newInstanceAfterOtherConstructorCall(){
新的TransacoryMethod();
新PublicFactoryMethod();
}
@FactoryMethodProperty(FactoryMethodKeys.IsFactoryMethod)
public静态PublicFactoryMethod newInstance(){
返回新的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."<init>":()V
         6: new           #1                  // class factoryMethodTest/PublicFactoryMethod
         9: invokespecial #20                 // Method "<init>":()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 "<init>":()V
         7: areturn
      LineNumberTable:
        line 55: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
}
#23=Utf8值
#24=Utf8 Lorg/opalj/fpa/测试/注释/工厂方法键;
#25=Utf8 IsFactoryMethod
{
公共静态void newInstanceAfterOtherConstructorCall();
描述符:()V
标志:ACC_公共,ACC_静态
运行时访问说明:
0: #16()
代码:
堆栈=1,局部变量=0,参数大小=0
0:new#17//class factoryMethodTest/TransFacoryMethod
3:invokespecial#19//Method factoryMethodTest/TransFacoryMethod.“:()V
6:new#1//class factoryMethodTest/PublicFactoryMethod
9:invokespecial#20//方法“”:()V
12:返回
LineNumberTable:
第49行:0
第50行:6
第51行:12
LocalVariableTable:
起始长度插槽名称签名
public static factoryMethodTest.PublicFactoryMethod newInstance();
描述符:()LfactoryMethodTest/PublicFactoryMethod;
标志:ACC_公共,ACC_静态
运行时访问说明:
0:16(#23=e#24.#25)
代码:
堆栈=2,局部变量=0,参数大小=0
0:new#1//class factoryMethodTest/PublicFactoryMethod
3:dup
4:invokespecial#20//方法“”:()V
7:轮到你了
LineNumberTable:
第55行:0
LocalVariableTable:
起始长度插槽名称签名
}

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

它不需要存在。在运行时,JVM构造一个可以检索的注释实例。此实例将使用注释本身的
.class
文件中的
默认值初始化。它被表示为

AnnotationDefault
属性是 某些
方法信息的属性表(§4.6),即
表示注释类型元素的
注释默认值
属性记录由
方法信息
结构

表示注释元素的每个
方法\u info
结构 类型最多可以包含一个
AnnotationDefault
属性Java 虚拟机必须使此默认值可用,以便 通过适当的反射API应用


您最终将调用注释实例的
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}