1. 程式人生 > >為什麼String類是final?

為什麼String類是final?

要理解這個問題,需要先了解以下幾點:
(1)immutable ——不可改變
(2)字串池——String pool

①immutable class/Object
不可改變類——是指類的狀態不變,一旦建立,狀態就是固定不變的
②字串池

String a = "HELLO";
String b = "HELLO";
String c = new String("HELLO");
String d = new String("HELLO");
System.out.println(a == b);
System.out.println(b == c);
System.out.println
(c == d); System.out.println(a.equals(b)); System.out.println(b.equals(c)); System.out.println(c.equals(d));

結果為:true,false,false,true,true,true
這裡就涉及到字串池,pools是為了提高JAVA記憶體利用率而採用的措施,當遇到String a = “HELLO”時,JAVA會先在字串池中查詢是否存在“HELLO”這個字串,如果沒有,則新建立一個物件,然後變數a指向這個地址,然後再遇到String b = “HELLO”時,由於字串池中以及有了“HELLO”這個物件,所以直接將變數b的地址指向“HELLO”,省去了重新分配的麻煩,如圖:
這裡寫圖片描述


在JAVA中,“==”對於兩個基本型別,判斷內容是否相等,對於物件判斷兩個物件的地址是否相等,所以此時的a,b的地址相等,返回true。
那麼String c = new String(“Hello”)又如何處理呢?如果是這種寫法,則不會去訪問字串池,而是先為變數 c 開闢空間,然後將值寫入空間。所以b == c返回false,c == d同樣返回false。至於String的equals方法,因為它比較的不是物件的地址,而是物件的值,所以都返回true就不奇怪了。
Java虛擬機器有一個字串池,儲存著幾乎所有的字串物件。字串表示式總是指向字串池中的一個物件。使用new操作建立的字串物件不指向字串池中的物件,但是可以使用intern方法使其指向字串池中的物件(注:如果池中已經有相同的 字串–使用equals方法確定,則直接返回池中的字串,否則先將字串新增到池中,再返回)。

既然已經理解了上述幾點後,再對該問題進行闡述:
1、只有當字串是不可變的,字串池才有可能實現。字串池的實現可以在執行時節約很多heap空間,因為不同的字串變數都指向池中的同一個字串。但如果字串是可變的,那麼String interning將不能實現(注:String interning是指對不同的字串僅僅只儲存一個,即不會儲存多個相同的字串。),因為這樣的話,如果變數改變了它的值,那麼其它指向這個值的變數的值也會一起改變。

2、如果字串是可變的,那麼會引起很嚴重的安全問題。譬如,資料庫的使用者名稱、密碼都是以字串的形式傳入來獲得資料庫的連線,或者在socket程式設計中,主機名和埠都是以字串的形式傳入。因為字串是不可變的,所以它的值是不可改變的,否則黑客們可以鑽到空子,改變字串指向的物件的值,造成安全漏洞。

3、因為字串是不可變的,所以是多執行緒安全的,同一個字串例項可以被多個執行緒共享。這樣便不用因為執行緒安全問題而使用同步。字串自己便是執行緒安全的。

4、類載入器要用到字串,不可變性提供了安全性,以便正確的類被載入。譬如你想載入java.sql.Connection類,而這個值被改成了myhacked.Connection,那麼會對你的資料庫造成不可知的破壞。

5、因為字串是不可變的,所以在它建立的時候hashcode就被快取了,不需要重新計算。這就使得字串很適合作為Map中的鍵,字串的處理速度要快過其它的鍵物件。這就是HashMap中的鍵往往都使用字串。