1. 程式人生 > >String為何被設計為不可變的

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.字串物件不可變讓它們可以被共享。

JDK原始碼,java.lang.String類

    看原始碼第一行,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,那麼會對你的資料庫造成不可知的破壞。