Java基础--String、StringBuffer、StringBuilder
1.是否可变
- String不可变
- StringBuffer、StringBuilder可变
2.是否线程安全
- String不可变,因此是线程安全的
- StringBuffer内部使用synchronized实现同步,是线程安全的
- StringBuilder仅支持单线程,是非线程安全的
3.关于String不可变:
String s1 = "abc";
String s1 = s1 + "def";
以上代码中,JVM具体实现步骤为:在共享池中创建对象“abc”并赋给s1引用;创建新的s1引用,将原来s1指向的字符串尾部加“def”赋值给它;回收原来的s1。(s1并没有变,修改时要进行新建和回收)
4.String不可变原因:
a.便于缓存散列值
因为String的hash值经常被使用,例如String use做HashMap的key。不可变的特性可以使得hash值也不可变,因此只需要进行一次计算。
b.字符串池的需要
如果一个String对象已经被创建过了,那么就会从String Pool中取得引用。只有String是不可变的,才可能使用String Pool。

c.安全性
String不可变性可以保证参数不可变。例如在作为网络连接参数的情况下如果String是可变的,那么在网络连接过程中,String被改变,改变String对象的那一方以以现在连接的是其它主机,而实际情况却不一定是。
d.线程安全
字符串不可变性天生具备线程安全,可以在多个线程中安全地使用。
5.关于String.intern()
使用String.intern()可以保证相同内容的字符串实例引用相同的内存对象。
下面示例中,s1和s2分别指向字符串共享池同一对象,s3和s4采用new String()的方式在堆中新建了两个不同对象,而s5是通过 s3.intern() 方法取得一个对象引用,这个方法首先把s3引用的对象放到共享池中,然后返回这个对象引用。因此 s5 和 s1 引用的是同一个字符串常量池的对象。
public class StringTest { public static void main(String[] args) { String s1 = "abc"; String s2 = "abc"; String s3 = new String("abc"); String s4 = new String("abc"); String s5 = s3.intern(); String s6 = s1.intern(); System.out.println(s1 == s2); //true 指向共享池中同一内存地址 System.out.println(s3 == s4); //false 指向不同的堆内存地址 System.out.println(s2 == s3); //false 一个指向共享池,一个指向堆 System.out.println(s3 == s5); //false 一个指向堆,一个指向共享池 System.out.println(s1 == s5); //true 指向共享池中同一内存地址 System.out.println(s1 == s6); //true 指向共享池中同一内存地址 } }
Java 虚拟机将堆划分成新生代、老年代和永久代(PermGen Space)。在Java6之前,字符串常量池被放在永久代中,而在 Java7时,它被放在堆的其它位置。这是因为永久代的空间有限,如果大量使用字符串的场景下会导致 OutOfMemoryError 错误。

浙公网安备 33010602011771号