加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – 字符串文字,实习和反思

发布时间:2020-12-14 19:28:43 所属栏目:Java 来源:网络整理
导读:我试图找到第三个解决方案 this question. 我不明白为什么不打印错误. public class MyClass { public MyClass() { try { Field f = String.class.getDeclaredField("value"); f.setAccessible(true); f.set("true",f.get("false")); } catch (Exception e)
我试图找到第三个解决方案 this question.

我不明白为什么不打印错误.

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));
    }
}

当然,由于字符串的实习,被修改的“真实”实例与PrintStream的打印方法中使用的实例完全相同?

public void print(boolean b) {
    write(b ? "true" : "false");
}

我失踪了什么

编辑

@yshavit的一个有趣的一点是,如果你添加行

System.out.println(true);

在尝试之前,输出是

true
false

解决方法

这可以说是一个HotSpot JVM错误.

问题在于字符串文字实习机制.

>在常量池解析过程中,字符串文字的java.lang.String实例被懒惰地创建.
>最初,字符串字面值在CONSTANT_String_info结构指向CONSTANT_Utf8_info的常量池中表示.
>每个类都有自己的常量池.也就是说,MyClass和PrintStream对于文字“true”有自己的一对CONSTANT_String_info / CONSTANT_Utf8_info cpool条目.
>当第一次访问CONSTANT_String_info时,JVM启动解析过程.字符串实习是这个过程的一部分.
>要找到一个文字被匹配的匹配项,JVM将CONSTANT_Utf8_info的内容与StringTable中的字符串实例的内容进行比较.
> ^^^这是问题.将来自cpool的原始UTF数据与可通过Reflection进行欺骗的Java char []数组内容进行比较.

那么,你的测试发生了什么?

> f.set(“true”,f.get(“false”))在MyClass中启动文字“true”的解析.
> JVM发现StringTable中没有匹配序列’true’的实例,并创建一个新的java.lang.String,它存储在StringTable中.
> String从StringTable的值的值将通过Reflection替换.
> System.out.println(true)在PrintStream类中启动文字“true”的解析.
> JVM将UTF序列’true’与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!");
        }
    }
}

JVM的一个可能的修复是将一个指向StringTable中的原始UTF序列的指针以及java.lang.String对象存储在一起,因此实际进程不会将cpool数据(用户无法访问)与值数组(可通过Reflection进行访问)进行比较.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读