2016-06-16 71 views
20

儘管重複使用字符串常量和字面量,以下代碼片段將打印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() {} 
} 
+0

註釋字符串文字不是代碼的一部分,並沒有受到相同的規則在代碼字符串文字標註值,所以他們應該彙集在一起​​真的沒有理由。 – EJP

回答

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爲代表的本地方法。你可以在這裏看到代碼native implementation getUFT8At。解析的常量永遠不會被攔截,也不會從StringTable(其中字符串被攔截)檢索。

我認爲這可能是實施的一種選擇。創建實習是爲了在字符串文字之間進行更快速的比較,因此僅用於在實施方法中可用的實習文字。

4

這是因爲您在運行時訪問註釋,並且符合java spec - Example 3.10.5-1. String Literals,字符串是新創建的,因此是不同的。

所有文字字符串和編譯時字符串值的常量 表達式將被自動扣留

在你的情況從test1值將在從原生值運行時間計算()方法(看AnnotationDefault attribute )。

String value() default CONSTANT; 

其他情況也將在運行時計算。

當你從你必須明確地執行實習生

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