Pau*_*ton 10 java string reflection jvm
我正试图找到这个问题的第三个解决方案.
我不明白为什么这不打印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));
}
}
Run Code Online (Sandbox Code Playgroud)
当然,由于字符串实习,"true"被修改的实例与print方法中使用的实例完全相同PrintStream?
public void print(boolean b) {
write(b ? "true" : "false");
}
Run Code Online (Sandbox Code Playgroud)
我错过了什么?
编辑
@yshavit的一个有趣的观点是,如果你添加这条线
System.out.println(true);
Run Code Online (Sandbox Code Playgroud)
之前try,输出是
true
false
Run Code Online (Sandbox Code Playgroud)
这可以说是一个HotSpot JVM错误.
问题出在字符串文字实习机制中.
java.lang.String 字符串文字的实例是在常量池解析期间懒惰创建的.CONSTANT_String_info指向的结构在常量池中表示CONSTANT_Utf8_info.MyClass并为文字'true'PrintStream设置了自己的CONSTANT_String_info/ CONSTANT_Utf8_infocpool条目对.CONSTANT_String_info第一次访问时,JVM启动解析过程.字符串实习是此过程的一部分.CONSTANT_Utf8_info与字符串实例的内容进行比较StringTable.char[]用户通过Reflection欺骗的Java 数组内容进行比较.那么,你的测试中发生了什么?
f.set("true", f.get("false"))启动文字"真实"的解决方案MyClass.StringTable匹配序列'true'时没有发现任何实例,并创建一个java.lang.String存储在其中的新实例StringTable.valueStringTable通过Reflection替换了String from .System.out.println(true)在课堂上启动文字'true'的解析PrintStream.StringTable,但没有找到匹配项,因为该String已经有'false'值.另一个'true'字符串被创建并放入StringTable.为什么我认为这是一个错误?
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!");
}
}
}
Run Code Online (Sandbox Code Playgroud)
JVM的一个可能的修复方法是将指向原始UTF序列的指针StringTable与java.lang.String对象一起存储,这样实习过程就不会将cpool数据(用户不可访问)与value数组(可通过Reflection访问)进行比较.
| 归档时间: |
|
| 查看次数: |
325 次 |
| 最近记录: |