-
使用雙引號建立字串時,JVM會現在字串常量池中查詢是否已存在該字串,存在則返回,不存在則在池中建立後再返回。與此同時,使用String的
intern
方法也是類似處理。 -
使用
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
指向的是同一個物件。 -
new String("123")建立了幾個物件?一個或兩個。先從常量池中查詢123,有則建立,沒有則不建立;new會新建立一個物件。
String為什麼不可變
不能被繼承;未提供能改變它狀態的公共方法;它的工具方法都是返回一個新的字串。
String不可變有什麼好處
-
String常量池的必要條件。String常量池就是一個由JVM建立的特殊記憶體區域,用於存放字串常量,當建立一個字串時,JVM先去池中尋找是否存在,存在則返回,不存在則建立。即多個具有相同字元序列的字串引用會指向池中同一個物件。如果有一個引用變數對其修改,那其他引用變數的值隨之修改,快取就無意義了。說到這裡,我想到了平時寫快取程式碼的邏輯,我們使用Redis來快取重要物件資料的時候,當快取物件發生修改,我們會立即更新快取,那字串常量池也能這麼做嗎,能在常量池中實時更新它的值或內部狀態嗎?顯然是不能的。如果能修改,首先不能稱它為常量池了;其次這會大大提升它的使用難度,很多判斷物件相等的場景變得複雜了;其三,字串本質是字元序列,它不應該有複雜的內部狀態,越簡單越安全,否則它也不會被廣泛使用。
-
因為不可變,所以是執行緒安全的。
-
很適合作為
HashMap
的Key。String的hashCode
方法在第一次呼叫的時候會快取它的hash值,再次呼叫的時候無需再次計算。關於這一點,我們去看它的原始碼就會一目瞭然:將hash函式的計算結果賦值給String的成員變數hash
,第二次計算就能直接返回。從這裡可以看出,從HashMap
、HashSet
等使用hash函式計算元素位置的集合中查詢一個元素是非常快的。