String类为什么被设计为不可变的?
點擊上方?好好學java?,選擇?星標?公眾號
重磅資訊、干貨,第一時間送達 今日推薦:都說了多少遍,不要再學 JSP 了!個人原創100W+訪問量博客:點擊前往,查看更多從哪看出來String類是不可變的?
public?final?class?Stringimplements?java.io.Serializable,?Comparable<String>,?CharSequence?{/**?The?value?is?used?for?character?storage.?*/private?final?char?value[];
}
String類的值是保存在value數組中的,并且是被private final修飾的
private修飾,表明外部的類是訪問不到value的,同時子類也訪問不到,當然String類不可能有子類,因為類被final修飾了
final修飾,表明value的引用是不會被改變的,而value只會在String的構造函數中被初始化,而且并沒有其他方法可以修改value數組中的值,保證了value的引用和值都不會發生變化
final關鍵字的作用有如下幾種
final修飾類時,表明這個類不能被繼承
final修飾方法,表明方法不能被重寫
final修飾變量,如果是基本數據類型的變量,則其數值一旦在初始化之后便不能改變;如果是對象類型的變量,只能保證它的引用不變,但對象的內容是可以改變的
在Java中數組也是對象,數組即使被final修飾,內容還是可以改變的
所以我們說String類是不可變的。
附上我歷時三個月總結的?Java 面試 + Java 后端技術學習指南,筆者這幾年及春招的總結,github 1.1k star,拿去不謝!
下載方式
1.?首先掃描下方二維碼
2.?后臺回復「Java面試」即可獲取
而很多方法,如substring并不是在原來的String類上進行操作,而是生成了新的String類
public?String?substring(int?beginIndex)?{if?(beginIndex?<?0)?{throw?new?StringIndexOutOfBoundsException(beginIndex);}int?subLen?=?value.length?-?beginIndex;if?(subLen?<?0)?{throw?new?StringIndexOutOfBoundsException(subLen);}return?(beginIndex?==?0)???this?:?new?String(value,?beginIndex,?subLen); }為什么String被設置為不可變的?
字符串常量池
字符串常量池可以節省大量的內存空間。如果String類可變就不可能有字符串常量池
字符串常量池放在哪?
jdk1.7之前的不討論,從jdk1.7開始,字符串常量池就開始放在堆中,然后本文的所有內容都是基于jdk1.8的
下面這個代碼還是經常被問到的
String?str1?=?"abc"; String?str2?=?"abc"; String?str3?=?new?String("abc"); String?str4?=?new?String("abc"); //?true System.out.println(str1?==?str2); //?false System.out.println(str1?==?str3); //?false System.out.println(str3?==?str4);內存中的結構如下其中常量池中存的是引用
解釋一下上面代碼的輸出,Java中有2種創建字符串對象的方式
String?str1?=?"abc"; String?str2?=?"abc"; //?true System.out.println(str1?==?str2);采用字面值的方式創建一個字符串時,JVM首先會去字符串池中查找是否存在"abc"這個對象的引用
如果不存在,則在堆中創建"abc"這個對象,并將其引用添加到字符串常量池(實際上是將引用放到哈希表中),隨后將引用賦給str1
如果存在,則不創建任何對象,直接將池中"abc"對象的引用返回,賦給str2。因為str1、str2指向同一個對象,所以結果為true。
String?str3?=?new?String("abc"); String?str4?=?new?String("abc"); //?false System.out.println(str3?==?str4);采用new關鍵字新建一個字符串對象時,JVM首先在字符串池中查找有沒有"abc"這個字符串對象的引用
如果沒有,則先在堆中創建一個"abc"字符串對象,并將引用添加到字符串常量池,隨后將引用賦給str3
如果有,則不往池中放"abc"對象的引用,直接在堆中創建一個"abc"字符串對象,然后將引用賦給str4。這樣,str4就指向了堆中創建的這個"abc"字符串對象;
因為str3和str4指向的是不同的字符串對象,結果為false。
緩存HashCode
String類在被創建的時候,hashcode就被緩存到hash成員變量中,因為String類是不可變的,所以hashcode是不會改變的。這樣每次想使用hashcode的時候直接取就行了,而不用重新計算,提高了效率
public?final?class?Stringimplements?java.io.Serializable,?Comparable<String>,?CharSequence?{/**?Cache?the?hash?code?for?the?string?*/private?int?hash;?//?Default?to?0}可以用作HashMap的key
由于String類不可變的特性,所以經常被用作HashMap的key,如果String類是可變的,內容改變,hashCode也會改變,當根據這個key從HashMap中取的時候有可能取不到value,或者取到錯的value
線程安全
不可變對象天生就是線程安全的,這樣可以避免在多線程環境下對String做同步操作
最后,再附上我歷時三個月總結的?Java 面試 + Java 后端技術學習指南,筆者這幾年及春招的總結,github 1.1k star,拿去不謝!
下載方式
1.?首先掃描下方二維碼
2.?后臺回復「Java面試」即可獲取
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的String类为什么被设计为不可变的?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 7个IntelliJ IDEA必备插件,
- 下一篇: Java 集合框架看这一篇就够了