《深入Java虚拟机》代码2-7 String.intern()示例代码问题

10/22/2020 jvm

# 《深入Java虚拟机》代码2-7 String.intern()示例代码问题

# 环境说明

openjdk7u11 自己从源码编译的版本

# 源码

参考书上的源码

public class FunWithIntern {
    public static void main(String[] args) {
        String str1 = new StringBuilder("沙").append("发").toString();
        System.out.println(str1.intern() == str1);

        String str2 = new StringBuilder("ja").append("va").toString();
        System.out.println(str2.intern() == str2);

        String str3 = new StringBuilder("open").append("jdk").toString();
        System.out.println(str3.intern() == str3);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

上述程序运行的结果为

true
true
false
1
2
3

与书上的说明不符 按书上的说明,由于jdk1.7中,String.intern()返回的是首次出现的字符串的引用,所以对于str1,由于str1即字符串”沙发“在环境中第一次出现,str1.intern()返回的是str1的引用,所以str1.intern()==str1结果为true 问题出在str2,书上说字符串**"java"不是在此方法中第一次出现,因此在运行此程序之前,即环境初始化时已有字符串"Java"**,所以理论str2.intern()==str2结果应为false,然而实际运行中,此方法仍旧为true,即环境中预先不存在此字符串,与书中描述不符

# 探秘

实际中,书中指的预先存在的字符串是在System类初始化中定义的,查看System类源码

public final class System {

    /* register the natives via the static initializer.
     *
     * VM will invoke the initializeSystemClass method to complete             <===VM调用initializeSystemClass方法
     * the initialization for this class separated from clinit.
     * Note that to use properties set by the VM, see the constraints
     * described in the initializeSystemClass method.
     */
    private static native void registerNatives();
    static {
        registerNatives();
    }
//...
    private static void initializeSystemClass() {
//...
        sun.misc.VM.saveAndRemoveProperties(props);
        lineSeparator = props.getProperty("line.separator");
        sun.misc.Version.init();//                                             <===此方法中会调用sun.misc.Version.init()方法
   }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

注意上面两处箭头注释 :VM调用initializeSystemClass方法=>此方法中会调用sun.misc.Version.init()方法,而sun.misc.Version类如下

public class Version {
    private static final String launcher_name = "openjdk";
    private static final String java_version = "1.7.0-internal";
//...
}
1
2
3
4
5

在某些环境中上面的launcher_name的值为"java",第一个程序运行时,**"java"预先存在,str2.intern()==str2返回false 我的openjdk中"java"**预先不存在,str2.intern()==str2返回true,但str3.intern()==str3返回false

参考 https://blog.csdn.net/w605283073/article/details/72753494 (opens new window)

Last Updated: 1/22/2024, 8:56:53 AM