1. 程式人生 > >String被設計成不可變和不能被繼承的原因

String被設計成不可變和不能被繼承的原因

String是所有語言中最常用的一個類。我們知道在Java中,String是不可變的、final的。Java在執行時也儲存了一個字串池(String pool),這使得String成為了一個特別的類。

主要是為了 “ 效率 ”  “ 安全性 ” 的緣故。 String 允許被繼承由於它的高度被使用率可能會降低程式的效能,所以 String 被定義成 final

一:String 和其他基本型別不同 , 他是個物件型別既然是物件型別 , 如果是在靜態方法下是必須呼叫靜態方法或值的 , 如果是非靜態的方法 , 就必須要例項化.

main 函式是個 static 所以String 

要能像其他的基本型別一樣直接被呼叫這也是為什麼在 main 函式下使用 String 型別不會報告錯誤的原因..

一下就解釋了兩個心裡的疑問..

以前一直覺得奇怪 ,為什麼 String 是物件型別在 main 函式下卻是不需要例項化的再次佩服 java 設計人員想得真周到.

二:當定義 String 型別的靜態欄位(也成類欄位),可以用靜態變數(非 final)代替常量(final)加快程式速度。反之,對於原始資料型別,例如 int,也成立。

例如,你可能建立一個如下的 String 物件:

PrivatestaticfinalStringx="example";

對於這個靜態常量(由 final 

關鍵字標識),你使用常量的每個時候都會建立一個臨時的 String 物件。在位元組程式碼中,編譯器去掉 ”x”,代替它的是字串 “example”, 以致每次引用 ”x”  VM 都會進行一次雜湊表查詢。

相比之下,度於靜態變數 (  final 關鍵字 ),字串只建立一次。僅當初始化 “x” 時, VM 才進行雜湊表查詢。

還有另一個解釋 :

帶有 final 修飾符的類是不可派生的。 java 核心 API 中,有許多應用 final 的例子,例如 java.lang.String String 類指定 final 防止了人們覆蓋 length() 方法。

另外,如果指定一個類為 final

,則該類所有的方法都是 final java 編譯器會尋找機會內聯(inline)所有的 final 方法(這和具體的編譯器實現有關)。此舉能夠使效能平均提高 50%

示例:

publicclassTest{

publicstaticvoidmain(String[]args){

//

}

}

如果 String 不是 final 那麼就可以繼承

publicclassString2extendsString{

//..

//...

}

那我們的 main 也就可以寫成

publicclassTest{

publicstaticvoidmain(String2[]args){//注意此處

//

}

}

另外補充一點:

作用就是 final的類不能被繼承,不能讓別人繼承有什麼好處?

意義就在於,安全性,如此這般:

java 自出生那天起就是“為人民服務”,這也就是為什麼java做不了病毒,也不一定非得是病毒,反正總之就是為了安全,人家java的開發者目的就是不想讓 java幹這類危險的事兒,java並不是作業系統本地語言,換句話說java必須藉助作業系統本身的力量才能做事,JDK中提供的好多核心類比如 String,這類的類的內部好多方法的實現都不是java程式語言本身編寫的,好多方法都是呼叫的作業系統本地的API,這就是著名的“本地方法呼叫”,也只有這樣才能做事,這種類是非常底層的,和作業系統交流頻繁的,那麼如果這種類可以被繼承的話,如果我們再把它的方法重寫了,往作業系統內部寫入一段具有惡意攻擊性質的程式碼什麼的,這不就成了核心病毒了麼?

上面所述是最重要的,另外一個方面,上面2位老兄說的也都很對, 就是不希望別人改,這個類就像一個工具一樣,類的提供者給我們提供了,就希望我們直接用就完了,不想讓我們隨便能改,其實說白了還是安全性,如果隨便能改了,那麼java編寫的程式肯定就很不穩定,你可以保證自己不亂改,但是將來一個專案好多人來做,管不了別人,再說有時候萬一疏忽了呢?他也不是估計的,所以這個安全性是很重要的,javaC++相比,優點之一就包括這一點;

原因絕對不只有這麼多,因為如果這些個核心的類都能被隨便操作的話,那是很恐怖的,會出現好多好多未知的錯誤,莫名其妙的錯誤….

String類不可變性的好處

只有當字串是不可變的,字串池才有可能實現。字串池的實現可以在執行時節約很多heap空間,因為不同的字串變數都指向池中的同一個字串。但如果字串是可變的,那麼String interning將不能實現(譯者注:String interning是指對不同的字串僅僅只儲存一個,即不會儲存多個相同的字串。),因為這樣的話,如果變數改變了它的值,那麼其它指向這個值的變數的值也會一起改變。

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

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

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

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