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() {}
}
intern() in Java. All compile-time constant strings in Java are automatically interned using this method. String interning is supported by some modern object-oriented programming languages, including Java, Python, PHP (since 5.4), Lua,Julia and . NET languages.
Yes. In general any literal string, identifier, or other constant string in JS source is interned. However implementation details (exactly what is interned for instance) varies, as well as when the interning occurs.
It is also possible to use multiple annotations on the same declaration: @Author(name = "Jane Doe") @EBook class MyClass { ... } If the annotations have the same type, then this is called a repeating annotation: @Author(name = "Jane Doe") @Author(name = "John Smith") class MyClass { ... }
Annotations are used to provide supplemental information about a program. Annotations start with '@'. Annotations do not change the action of a compiled program. Annotations help to associate metadata (information) to the program elements i.e. instance variables, constructors, methods, classes, etc.
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.
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With