StringPool(字符串常量池)

字符串常量池的解释 字符串常量池(String Pool)保存着所有字符串字面量(literal strings),这些字面量在编译时期就确定哪些是要放入字符串常量池。具体来说,只有使用双引号("")创建的字符串字面量才会被认为是常量,从而被放入常量池中。 在运行时,还可以使用 String 的 intern() 方法在运行过程将字符串添加到 String Pool 中。调用该方法会判断字符串常量池是否有该字面量,如没有,会在字符串常量池创建。之后,会返回字符串常量池中的对象。 通过new创建的字符串字面量,会先将,无论是否在字符串常量池存在,都会创建新的对象且不放入字符串常量池。 String str1 = "Hello world!"; String str2 = "Hello world!"; String str3 = new String("Hello world!"); String str4 = new String("Hello world!"); String str5 = str4.intern();//运行过程中把字符串添加到String Pool,并返回String Pool中的对象 System.out.println(str1 == str2);//运行结果:true。 System.out.println(str1 == str3);//运行结果:false。 System.out.println(str3 == str4);//运行结果:false。 System.out.println(str1 == str5);//运行结果:true。 System.out.println(str4 == str5);//运行结果:false。 字符串常量池长度 在 jdk6中,StringTable的长度是固定的,就是1009的长度。所以如果常量池中的字符串过多,会产生hash冲突,导致链表变长,降低查询效率。 在jdk7中,StringTable的长度可以通过一个参数指定: -XX:StringTableSize=99991 字符串常量池的位置 不同版本的Java虚拟机(JVM)可能会采用不同的方式来实现字符串常量池,并且在不同的JVM实现中,字符串常量池的位置也可能会发生变化。 JDK 6 字符串常量池存在于运行时常量池,运行时常量池存在方法区。方法区的实现为永久代(PermGen)。 PermGen默认大小只有4m,这种设计可能会导致PermGen空间溢出(java.lang.OutOfMemoryError: PermGen space)的问题,并且在频繁加载大量类文件时容易出现性能问题。 JDK 7 为了解决这些问题,从 JDK 7 开始,字符串常量池被移动到了堆内存中。 JDK 8 还是在堆内存中。 字符串的拼接 如果定义字符串时有拼接的表达式,编译器会根据表达式的参数是否为"“直接引用来判断是否将字符串字面量放入字符串常量池。 如表达式"Hello”+" world!",编译器会将两个字符串拼接成一个新的字符串"Hello world!",然后对比这个新字符串对象和常量池中的字符串字面量"Hello world!“是否相同。由于Java字符串常量池的特性,当两个字符串的内容相同时,它们所引用的字符串对象实例也是相同的。因此,表达式"Hello”+" world!" == “Hello world!“的结果为true。 ...

January 9, 2025 · 2 min

String的value数组不可变的好处

缓存hash值 String中用value数组来存储字符串信息,用hash来缓存value的hash值。如果value不是final,每次修改后需要重新计算hash,失去了缓存的意义,影响程序运行效率。 //java9及之后采用byte[],之前是char[] private final byte[] value; private int hash; // Default to 0 public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { hash = h = isLatin1() ? StringLatin1.hashCode(value) : StringUTF16.hashCode(value); } return h; } String Pool(常量池)复用需要 String Pool可以缓存已经创建的String对象。只有 String 是不可变的,才可能使用 String Pool。 安全性 由于String对象在创建后不可被修改,因此对于String类型的参数,其不可变性可以保证参数不会被意外或恶意地改变。 在网络连接过程中,一般需要传递服务器地址、端口号、用户名、密码等各种参数。如果这些参数使用可变的String类型来表示,那么在连接过程中,这些参数可能会被改变,导致实际连接的主机不同于预期。例如,某个客户端使用一个可变的String类型来表示服务器地址,然后在连接过程中修改了该字符串,将原本应该连接的服务器地址改成了另一个地址,从而导致最终连接到了错误的服务器上。 如果使用不可变的String类型来表示这些参数,则可以避免上述问题的出现。由于String对象不可被修改,因此无论在何种情况下都可以确保连接所需的参数不会在连接过程中被更改,从而确保连接行为的正确性和稳定性。 多线程 由于String的不可变,String具备线程安全性,可以在多线程中使用。

January 9, 2025 · 1 min