我正在尝试找到这个问题的第三种解决方案。
我不明白为什么这个不打印false。
false
public class MyClass { public MyClass() { try { Field f = String.class.getDeclaredField("value"); f.setAccessible(true); f.set("true", f.get("false")); } catch (Exception e) { } } public static void main(String[] args) { MyClass m = new MyClass(); System.out.println(m.equals(m)); } }
当然,由于使用字符串实习,"true"被修改的实例print与PrintStream?方法中使用的实例完全相同。
"true"
print
PrintStream
public void print(boolean b) { write(b ? "true" : "false"); }
我想念什么?
编辑
@yshavit有趣的一点是,如果您添加该行
System.out.println(true);
在之前try,输出为
try
true false
可以说这是HotSpot JVM错误。
问题在于字符串字面量的内部机制 。
java.lang.String
CONSTANT_String_info
CONSTANT_Utf8_info
MyClass
StringTable
char[]
那么,您的测试中发生了什么?
f.set("true", f.get("false"))
value
System.out.println(true)
为什么我认为这是一个错误?
JLS§3.10.5和JVMS§5.1需要包含相同的字符序列串文字必须指向的同一个实例java.lang.String。
但是,在下面的代码中,具有 相同 字符序列的两个字符串文字的解析导致 不同的 实例。
public class Test { static class Inner { static String trueLiteral = "true"; } public static void main(String[] args) throws Exception { Field f = String.class.getDeclaredField("value"); f.setAccessible(true); f.set("true", f.get("false")); if ("true" == Inner.trueLiteral) { System.out.println("OK"); } else { System.out.println("BUG!"); } } }
JVM的一个可能解决方法是将指向原始UTF序列的指针StringTable与java.lang.String对象一起存储,以便内部处理过程不会将cpool数据(用户无法访问)与value数组(可通过Reflection访问)进行比较。