18

以下代码段打印了 4 个不同的哈希码,尽管重用了字符串常量和文字。为什么字符串值不在注释元素上?

public class Foo {
    @Retention(RetentionPolicy.RUNTIME)
    @interface Bar {
        String CONSTANT = "foo";

        String value() default CONSTANT;
    }

    public static void main(String[] args) throws Exception {
        System.out.println(System.identityHashCode(Bar.CONSTANT));
        System.out.println(System.identityHashCode(Foo.class.getMethod("test1").getAnnotation(Bar.class).value()));
        System.out.println(System.identityHashCode(Foo.class.getMethod("test2").getAnnotation(Bar.class).value()));
        System.out.println(System.identityHashCode(Foo.class.getMethod("test3").getAnnotation(Bar.class).value()));
    }

    @Bar
    public void test1() {}

    @Bar("foo")
    public void test2() {}

    @Bar(Bar.CONSTANT)
    public void test3() {}
}
4

2 回答 2

10

字符串文字是实习的,但注释需要解析,它们存储在字节数组中。如果您查看课程,java.lang.reflect.Method您会看到:

private byte[]              annotations;
private byte[]              parameterAnnotations;
private byte[]              annotationDefault;  

也看一下public Object getDefaultValue()同一个类的方法,看看AnnotationParser是怎么调用的。流程一直持续到这里 AnnotationParser.parseConst并输入

case 's':
  return constPool.getUTF8At(constIndex);

该方法ConstantPool.getUTF8At是本机方法的委托。您可以在此处查看 本机实现 getUFT8At的代码。解析后的常量永远不会被实习,也永远不会从 StringTable(字符串被实习的地方)中检索到。

我认为这可能是一种实施方式。已创建实习以在字符串文字之间进行更快速的比较,因此仅用于在方法实现中可用的实习文字。

于 2016-06-17T12:38:28.170 回答
4

这是因为您在运行时访问注释并符合java 规范 - 示例 3.10.5-1。String Literals,字符串是新创建的,因此是不同的。

所有文字字符串和编译时字符串值的常量表达式都被自动实习

在您的情况下,值 fromtest1将在运行时从本机 value() 方法计算(查看AnnotationDefault 属性)。

String value() default CONSTANT;

其他情况也将在运行时计算。

当您从注释中获取值时,您必须明确执行实习

String poolString = Foo.class.getMethod("test1").getAnnotation(Bar.class).value().intern();
System.out.println(poolString == Bar.CONSTANT); 
于 2016-07-07T09:45:54.030 回答