java - Java 注解的默认值是否被编译成字节码?

标签 java annotations java-8 bytecode

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

我的注释:

@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."<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
}

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

最佳答案

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

The AnnotationDefault attribute is a variable-length attribute in the attributes table of certain method_info structures (§4.6), namely those representing elements of annotation types. TheAnnotationDefault attribute records the default value for the element represented by the method_info structure.

Each method_info structure representing an element of an annotation type may contain at most one AnnotationDefault attribute. The Java Virtual Machine must make this default value available so it can be applied by appropriate reflective APIs.

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

关于java - Java 注解的默认值是否被编译成字节码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32995042/

相关文章:

java - Hibernate 不断为我的枚举创建表

macos - 如何在 OS-X 上同时运行两个不同版本的 Java?

java-8 - Android Studio 3.0 Canary 2 仍然需要 Java 8 的 Jack

java - 尝试使用java和clojure在eclipse中创建maven动态Web项目

java - 给定整数列表上的迭代器,如何返回偶数上的迭代器?

java - 在 @Scheduled 注解中注入(inject) bean 属性

java - 为什么我们首先需要 isPrimitive() ?

java - spring-boot 创建 logging.path_IS_UNDEFINED.log 文件

java - assertEquals(Double, Double) 和 assertEquals(double, double, delta) 之间的 Junit 区别

javascript - TypeScript 空对象文字类型注解