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 错误。

 

posted @ 2018-04-08 19:23  旺仔小平头  阅读(136)  评论(0)    收藏  举报