Java 字符串常量池

首先看下面一段代码:

public class StringTest {
    public static final String S = "Hello";

    private String s = "Hello";

    public static void main(String[] args) {
        String s1 = "Hello";
        String s2 = "Hello";
        String s3 = new String("Hello");
        String s4 = new String("Hello");
        String s5 = new String("Hello").intern();
        String s6 = "Hello".intern();

        StringTest st = new StringTest();
        System.out.println(s1 == st.s); // true
        System.out.println(s1 == StringTest.S); // true
        System.out.println(s1 == s2); // true
        System.out.println(s1 == s3); // false
        System.out.println(s3 == s4); // false
        System.out.println(s1 == s5); // true
        System.out.println(s1 == s6); // true

        System.out.println(s1.equals(s2) + " " + s1.equals(s3) + " " + s3.equals(s4) + " " + s1.equals(s5) + " " + s1.equals(s6));
    }
}

运行在 JDK 17 上.
这是除了 StringTest.S 这个静态字段之外的其他是 "Hello" 的字符串在内存的表示. 可以得出:

  1. 除了 s3, s4 其它都指向同一个内存对象.
  2. 所有这些字符串都指向同一个 byte[], 里面存储的是 “Hello” 的 ascii 码.
    stringAddr.png
    静态字段, 静态字段也同其它字面量一样, 都指向同一个.
    class_static.png

这段代码里面, 有声明字面量(literal) 和 String 对象. 所有的字面量(常量或变量)都是指向内存字符串常量池的同一个字符串地址, 所以使用 == 对比也是相等的.

Java 常量池是什么?

Java 的字符串都是 Immutable 的, 也就是更改都会产生新的字符串. 常量池是在内存中开辟出来的一块专门存储字符串的空间. 由 String 类管理(native 代码). 它是一个很大的 HashMap 维护.

Java 常量池存在的意义什么?

所谓池, 就是共享同一份. 因为对很多程序来说, 很多字符串都是反复使用, 只要内存保存一份就好了.

为什么 new String() 不能返回常量池字符串?

常量池大小调节

可以看到如下参数, 默认是 65536. 调的太小, 容易产生hash 碰撞. 如果字符串不多, 调的太大, 占用太多空间.

uintx StringTableSize                          = 65536                                     {product} {default}

标签: none

添加新评论