Java筆記2:String,StringBuilder,StringBuffer

String、StringBuilder和StringBuffer的區別

String StringBuilder StringBuffer
是否可變 不可變 可變 可變
線程安全 安全1 不安全 安全
拼接方法 +concat方法 append方法 append方法
拼接性能 最差2 最好 中間3
適用情況 很少字符串操作 單線程大量字符串操作 多線程大量字符串操作
  1. 不可變對象天然是線程安全的,因爲其只可讀,不可寫。
  2. 在拼接兩個String對象時,會創建一個新的String對象保存拼接的結果,因此性能較差,並且會產生較多的內存垃圾。而如果拼接的都是字符串字面量,會在編譯時期優化。
  3. StringBuffer由於要保證線程安全,因此比StringBuilder的性能差。

String類的不可變性

如何保證不可變性

       Java中String類的源碼前兩行如下(版本是jdk_1.8.0_221):

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

    // ...
}

在Java9以前字符串採用char[]數組來保存字符,因此字符串的每個字符佔2字節;從Java9開始,字符串採用byte[]數組再加一個encoding-flag字段來保存字符,因此Java9的字符串更加節省空間。

    Java通過以下措施聯合保證了String類的不可變性:

  • final修飾value成員字段,保證其不被修改爲其他數組對象。
  • String類的所有方法都不會修改value字段中的任何元素。
  • final修飾String類,將其設計爲不可繼承的,保證了value字段不會被子類獲取到。

不可變性的優點

  • 字符串不變保證了哈希值不變,因此String類中緩存了哈希值,當字符串對象作爲HashMap的鍵時,能夠提高效率。
  • 字符串對象作爲Java中非常常見的對象,針對字符串對象的空間優化能夠大幅降低JVM的內存開銷。其不變性讓**字符串常量池(String Pool)**成爲可能:
    • 採用字面值的方式創建一個字符串時(如String str = "aaa";),JVM首先會去字符串池中查找是否存在"aaa"這個對象,如果不存在,則在字符串池中創建"aaa"這個對象,然後將池中"aaa"這個對象的引用地址返回給字符串常量str,這樣str會指向池中"aaa"這個字符串對象;如果存在,則不創建任何對象,直接將池中"aaa"這個對象的地址返回,賦給字符串常量。
    • 採用new關鍵字新建一個字符串對象時(如String str2 = new String("aaa")),JVM首先在字符串池中查找有沒有"aaa"這個字符串對象,如果有,則不在池中再去創建"aaa"這個對象了,直接在堆中創建一個"aaa"字符串對象,然後將堆中的這個"aaa"對象的地址返回賦給引用str2;如果沒有,則首先在字符串池中創建一個"aaa"字符串對象,然後再在堆中創建一個"aaa"字符串對象,然後將堆中這個"aaa"字符串對象的地址返回賦給str2引用。
    • 字符串的常量池能夠減少相同字符串的重複創建,優化空間。
  • 不可變對象是線程安全的,同一個字符串實例可以被多個線程共享。
  • 類加載器要用到字符串,不可變性提供了安全性,以便正確的類被加載。

    總的來說,字符串的不可變設計是考慮到效率和安全性的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章