String知識點整理

xfcoding發表於2023-04-16
  1. 使用雙引號建立字串時,JVM會現在字串常量池中查詢是否已存在該字串,存在則返回,不存在則在池中建立後再返回。與此同時,使用String的intern方法也是類似處理。

  2. 使用new String的方式建立,或者使用+拼接變數時,JVM都會重新建立一個新物件。比如下面:

    String s1 = "1";
    String s2 = "12";
    String s3 = s1 + "2";
    System.out.println(s2 == s3); // false
    

    因為s1是引用變數,JVM在編譯期不能確定s1的值,所以會在堆中新建立一個物件指向s3。如果s1加個final限制,讓s1能在編譯階段確定下來,它就是常量,因此在編譯時,s1 + "2"就會被最佳化成12。

    final String s1 = "1";
    String s2 = "12";
    String s3 = s1 + "2";
    System.out.println(s2 == s3); // true
    

    至於等號比較為什麼相等,是因為s2已經在常量池中了,s3被最佳化為了12,自然不會新建立了, 它跟s2指向的是同一個物件。

  3. new String("123")建立了幾個物件?一個或兩個。先從常量池中查詢123,有則建立,沒有則不建立;new會新建立一個物件。

String為什麼不可變

不能被繼承;未提供能改變它狀態的公共方法;它的工具方法都是返回一個新的字串。

String不可變有什麼好處

  • String常量池的必要條件。String常量池就是一個由JVM建立的特殊記憶體區域,用於存放字串常量,當建立一個字串時,JVM先去池中尋找是否存在,存在則返回,不存在則建立。即多個具有相同字元序列的字串引用會指向池中同一個物件。如果有一個引用變數對其修改,那其他引用變數的值隨之修改,快取就無意義了。說到這裡,我想到了平時寫快取程式碼的邏輯,我們使用Redis來快取重要物件資料的時候,當快取物件發生修改,我們會立即更新快取,那字串常量池也能這麼做嗎,能在常量池中實時更新它的值或內部狀態嗎?顯然是不能的。如果能修改,首先不能稱它為常量池了;其次這會大大提升它的使用難度,很多判斷物件相等的場景變得複雜了;其三,字串本質是字元序列,它不應該有複雜的內部狀態,越簡單越安全,否則它也不會被廣泛使用。

  • 因為不可變,所以是執行緒安全的。

  • 很適合作為HashMap的Key。String的hashCode方法在第一次呼叫的時候會快取它的hash值,再次呼叫的時候無需再次計算。關於這一點,我們去看它的原始碼就會一目瞭然:將hash函式的計算結果賦值給String的成員變數hash,第二次計算就能直接返回。從這裡可以看出,從HashMapHashSet等使用hash函式計算元素位置的集合中查詢一個元素是非常快的。

相關文章