【问题标题】:Why are annotation string values not interned?为什么注释字符串值没有被实习?
【发布时间】:2016-10-17 14:47:47
【问题描述】:

以下 sn-p 打印 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() {}
}

【问题讨论】:

  • 注解字符串字面量不是代码的一部分,也不受代码中字符串字面量规则的约束,因此没有理由将它们汇集起来。

标签: java annotations constants string-interning


【解决方案1】:

这是因为你在运行时访问注解并且按照java spec - Example 3.10.5-1. String Literals,字符串是新创建的,因此是不同的。

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

在您的情况下,test1 的值将在运行时通过本机 value() 方法计算(查看AnnotationDefault attribute)。

String value() default CONSTANT;

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

当你从注解中得到一个值时,你必须明确地执行实习

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

【讨论】:

    【解决方案2】:

    字符串文字是实习的,但注释需要解析,它们存储在字节数组中。如果您查看 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 是本机方法的委托。你可以在这里看到代码native implementation getUFT8At。解析后的常量永远不会被实习,也永远不会从 StringTable(字符串被实习的地方)中检索到。

    我认为这可能是一种实施方式。 Interning 的创建是为了更快速地比较 String 字面量,因此仅用于方法实现中可用的 interning 字面量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-27
      • 2013-01-06
      • 2012-05-21
      • 2023-03-28
      • 1970-01-01
      • 2016-08-29
      • 2011-01-29
      • 1970-01-01
      相关资源
      最近更新 更多