String為何被設計為不可變的
String類為什麼是final的
1. 首先我們先要理解final的用途:
final表示最終的意思
用final修飾符既可以修飾類、方法,也可以修飾變數
用final修飾的類不能被繼承
用final修飾的方法不可重寫
用final修飾的變數最多隻能賦值一次 值不可變
什麼是不可變類?
不可變類是指,一旦一個類的物件被創建出來,在其整個生命週期中,它的成員變數就不能被修改
2. String為什麼要用final修飾?
原始碼中對String為什麼設計成final的解釋:
Strings are constant; their values cannot be changed after they are created. String buffers support mutable strings. Because String objects are immutable they can be shared.
字串是恆定的,建立之後它們的值不能被改變。StringBuffer是可變的strings.字串物件不可變讓它們可以被共享。
看原始碼第一行,String類是用final關鍵字修飾,這說明String不可繼承。再看下面,欄位value是個char[ ]陣列,而且是用final修飾的。final修飾的欄位建立以後就不可改變。但是:雖然final代表了不可變,但僅僅是引用地址不可變,並不代表了陣列本身不會變,請看下面程式碼。
final int[] value={1,2,3}
int[] another={4,5,6};
value=another; //編譯器報錯,final不可變
value用final修飾,編譯器不允許我把value指向堆區另一個地址。但如果我直接對陣列元素動手,分分鐘搞定。
final int[] value={1,2,3};
value[2]=100; //這時候數組裡已經是{1,2,100}
或者更粗暴的反射直接改,也是可以的。
final int[] array={1,2,3};
Array.set(array,2,100); //陣列也被改成{1,2,100}
3.String設計為不可變的好處:
final也可以將陣列本身改變的,這個時候,起作用的還有private,正是因為兩者保證了String的不可變性。
那麼為什麼保證String不可變呢,因為只有當字串是不可變的,字串池才有可能實現。字串池的實現可以在執行時節約很多heap空間,因為不同的字串變數都指向池中的同一個字串。但如果字串是可變的,那麼String interning將不能實現,因為這樣的話,如果變數改變了它的值,那麼其它指向這個值的變數的值也會一起改變。
如果字串是可變的,那麼會引起很嚴重的安全問題。譬如,資料庫的使用者名稱、密碼都是以字串的形式傳入來獲得資料庫的連線,或者在socket程式設計中,主機名和埠都是以字串的形式傳入。因為字串是不可變的,所以它的值是不可改變的,否則黑客們可以鑽到空子,改變字串指向的物件的值,造成安全漏洞。
因為字串是不可變的,所以是多執行緒安全的,同一個字串例項可以被多個執行緒共享。這樣便不用因為執行緒安全問題而使用同步。字串自己便是執行緒安全的。
因為字串是不可變的,所以在它建立的時候HashCode就被快取了,不需要重新計算。這就使得字串很適合作為Map中的鍵,字串的處理速度要快過其它的鍵物件。這就是HashMap中的鍵往往都使用字串。
類載入器要用到字串,不可變性提供了安全性,以便正確的類被載入譬如你想載入java.sql.Connection類,而這個值被改成了myhacked.Connection,那麼會對你的資料庫造成不可知的破壞。