对于StringTable的理解

String table又称为String pool,字符串常量池,其存在于堆中(jdk1.7之后改的)。最重要的一点,String table中存储的并不是String类型的对象,存储的而是指向String对象的索引,真实对象还是存储在堆中。

此外String table还存在一个hash表的特性,里面不存在相同的两个字符串。

此外String对象调用intern()方法时,会先在String table中查找是否存在于该对象相同的字符串,若存在直接返回String table中字符串的引用,若不存在则在String table中创建一个与该对象相同的字符串。

一道经典的面试题:

    public static void main(String[] args) {
        String str1 = "abc";
        String str2 = "ab" + "c";
        String str3 = new String("ab") + "c";
        String str4 = str3.intern();
        System.out.println(str1 == str2);
        System.out.println(str1 == str3);
        System.out.println(str1 == str4);
    }

分析上述代码的输出情况。

答案为 true,false,true;

第一个为true的原因是jvm存在编译期优化的机制,在编译期(javac *.java时)会将可以拼接的字符串常量帮你自动拼接了,此时由于String table中已经存在了,因此会让str2指向一个与str1相同的那块地址,因此为true。

第二个为false的原因在于,由于使用了new String(),运行过程中会在堆中重新开辟一个空间存储,与之前的常量字符串没啥关系,因此为false。

第三个为true原因在于,调用intern()方法时会把在String table中查找是否存在与其值相等的(并不是地址相等)的字符串,发现里面恰好存在,因此返回该存在的引用,String table中的就是str1,因此为true。

下图为对编译后的*.class文件反编译的结果

         0: ldc           #2                  // String abc
         2: astore_1
         3: ldc           #2                  // String abc
         5: astore_2
         6: new           #3                  // class java/lang/StringBuilder
         9: dup
        10: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
        13: new           #5                  // class java/lang/String
        16: dup
        17: ldc           #6                  // String ab
        19: invokespecial #7                  // Method java/lang/String."<init>":(Ljava/lang/String;)V
        22: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        25: ldc           #9                  // String c
        27: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        30: invokevirtual #10                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        33: astore_3
        34: aload_3
        35: invokevirtual #11                 // Method java/lang/String.intern:()Ljava/lang/String;
        38: astore        4
        40: return

0 和 2 行为str1和str2的常量导入部分,可以看出两者的“abc”来自同一个地方,因此第一个为true,对于str3而言利用StringBuilder拼接完成后调用toString()。因此跟str1地址坑定不同。对于str4,34,35,38行,调用了本地方法intern,从这看不出具体细节。

扫描二维码关注公众号,回复: 9812169 查看本文章
发布了38 篇原创文章 · 获赞 4 · 访问量 2145

猜你喜欢

转载自blog.csdn.net/gw_9527/article/details/103002455
今日推荐