Why are annotation string values not interned?

房东的猫 提交于 2019-12-06 16:59:06

问题


The following snippet prints 4 distinct hash codes, despite reusing a string constant and literal. Why are string values not interned on annotation elements?

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() {}
}

回答1:


String literal are interned but annotations are subject to parse and they are stored in byte arrays. If you look at the class java.lang.reflect.Method you can see this:

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

Take also a look at the method public Object getDefaultValue() of the same class to see how the AnnotationParser is called. The flow continues till here AnnotationParser.parseConst and enter in

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

The method ConstantPool.getUTF8At is a delegate to a native method. You can see the code here native implementation getUFT8At. The parsed constant is never interned and is never retrieved from the StringTable (where string are interned).

I think it could be a choice of implementation. Interning has been created to make more fast comparison between String literal and so is used only for interning literal usable in method implementation.




回答2:


It's because you access to annotation at runtime and accordance with java spec - Example 3.10.5-1. String Literals, strings are newly created and therefore distinct.

All literal strings and compile-time string-valued constant expressions are automatically interned

In your case the value from test1 will be computed at runtime from native value() method (look at AnnotationDefault attribute).

String value() default CONSTANT;

Others cases also will be computed at runtime.

When you get a value from the annotation you have to explicitly to perform intern

String poolString = Foo.class.getMethod("test1").getAnnotation(Bar.class).value().intern();
System.out.println(poolString == Bar.CONSTANT); 


来源:https://stackoverflow.com/questions/37853188/why-are-annotation-string-values-not-interned

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!