2

我有一个粗略的想法,但仍然想问是否有人知道为什么String作为注释默认值提供的常量会更改身份,即使它们引用静态常量也是如此。

为了说明,为什么这段代码会打印true, true, false, false.

@TestAnn
public class TestClass {

    public static final String STRING_CONSTANT = "SHOULD_BE_CONSTANT";

    @Retention(RetentionPolicy.RUNTIME)
    public @interface TestAnn {
        String value() default TestClass.STRING_CONSTANT;
    }
    public class OtherTestClass {
        String NOT_EVEN_STATIC = TestClass.STRING_CONSTANT;
    }
    private void run() throws Exception {

        System.out.println(STRING_CONSTANT == constantValue());

        System.out.println(STRING_CONSTANT == new OtherTestClass().NOT_EVEN_STATIC);

        String str1 = getClass().getAnnotation(TestAnn.class).value();
        System.out.println(STRING_CONSTANT == str1);

        String str2 = (String) TestAnn.class.getMethod("value").getDefaultValue();
        System.out.println(STRING_CONSTANT == str2);
    }
    private String constantValue() {
        return TestClass.STRING_CONSTANT;
    }
    public static void main(String[] args) throws Exception {
        new TestClass().run();
    }
}
4

2 回答 2

0

棘手的是,当使用基于其运行时类的反射value()或使用反射检索真实值时,基本上会创建一个新对象String对象(Type Object)并用字符串值填充,getDefaultValue()

因此,当您尝试使用 == 运算符比较对象时,它将返回 false,但 equal 将返回 true,因为它比较内容,

前两个示例返回 true,因为您引用了相同的对象,constantValue()返回相同的并NOT_EVEN_STATIC存储相同的引用

您可以参考这个问题来了解为什么使用 == 的字符串总是具有常量值总是相等的,例如 NOT_EVEN_STATIC

干杯

于 2018-02-07T11:50:36.280 回答
0

因为Stringin 中的值确实不是 intern String,所以让我们找到Stringin 注释的来源。

首先我们检查代码Class,它是如何创建注释数据的。

private AnnotationData createAnnotationData(int classRedefinedCount) {
    Map<Class<? extends Annotation>, Annotation> declaredAnnotations =
        AnnotationParser.parseAnnotations(getRawAnnotations(), getConstantPool(), this);
...
}

然后,转到AnnotationParser.parseAnnotations,我们发现:

private static Object parseConst(int tag, ByteBuffer buf, ConstantPool constPool) {
  ...
  case 's': return constPool.getUTF8At(constIndex);
  ...
}

所以从. AnnotationParser_ 让我们自己获取价值:StringConstantPool

Method m = Class.class.getDeclaredMethod("getConstantPool");
m.setAccessible(true);
ConstantPool pool = (ConstantPool) m.invoke(getClass());

然后获取 theString和它的实习值,并比较它们:

String str = pool.getUTF8At(9); // I find the index by traverse the pool, may different in your code
String intern = str.intern();
System.out.println(str == intern); // false
System.out.println(str == STRING_CONSTANT); // false
System.out.println(intern == STRING_CONSTANT); // true

所以StringfromConstantPool不是实习生价值。我在eclipse中检查了他们的id

str(id=371), 实习生(id=372)

所以事实是对常量 StringConstantPool执行了操作intern,但它返回了它所持有的原始值,而不是实习生。

于 2018-02-08T03:12:14.847 回答