String 对象内存分配策略
這個問題可以說是一個高頻的面試題目,以前把這個問題弄懂了,最近突然想到這個問題,一時間竟然沒有太好的思路了。所以花些時間整理一下其中的知識點。
一、內存分配策略
我們先來看一個題目(這個問題都快看吐了~),你知道正確的運行結果并給出解釋嗎。不知道也沒關系,我會在下面給出具體的分析。
@Testpublic void test() {String s1 = "abc";String s2 = "abc";String s3 = new String("abc");String s4 = new String("abc");System.out.println(s1 == s2); // trueSystem.out.println(s3 == s4); // falseSystem.out.println(s1 == s3); // false}String s = "" 與 String s = new String("") 兩種方式都可以創建字符串對象,它們有什么不同嗎。下面的解釋會涉及到 java 虛擬機內存區域 方面的知識,不知道的同學可以先了解一下。
1.1 創建對象的方式
String s = "abc" 方式創建的對象,存儲在字符串常量池中,在創建字符串對象之前,會先在常量池中檢查是否存在 abc 對象。如果存在,則直接返回常量池中 abc對象的引用,不存在會創建該對象,并將該對象的引用返回給對象 s。
以 HotSpot 虛擬機為例,在 jdk1.8 之前,字符串常量池在方法區中,為了減小方法區內存溢出的風險,在 jdk1.8 之后就把字符串常量池轉移到 java 堆中了。
String s = new String("abc") 這種方式,實際上 abc 本身就是字符串池中的一個對象,在運行 new String() 時,把字符串常量池中的字符串 abc 復制到堆中,因此該方式不僅會在堆中,還會在常量池中創建 abc 字符串對象。 最后把 java 堆中對象的引用返回給 s。
1.2 問題分析
通過上面的分析,大家應該對問題結果有一個感性的認識了。
s1 指向字符串常量池中的 abc 對象,s2 也指向字符串常量池中的 abc 對象,因此 s1 與 s2 指向的是同一個對象,故 s1 == s2 返回 true。
s3 與 s4 分別指向 java 堆中兩個不同的對象,因此 s3 == s4 是 false。
s1 與 s3 分別指向字符串常量池中的對象與 java 堆中的對象,s1 == s3 返回值也是 false。
二、問題擴展
上面的問題清楚了原理還很好理解,下面還有一個例子,理解起來就不那么容易了。
@Testpublic void test() {String s1 = "abc";String s2 = "a";System.out.println(s1 == ("a" + "bc")); // trueSystem.out.println(s1 == (s2 + "bc")); // false }2.1 字符串常量重載 "+"
"a" + "bc" 是兩個字符串常量的拼接,當一個字符串由多個字符串常量連接而成時,它自己也肯定是字符串常量。java 虛擬機對于字符串常量的 “+” 號連接,在程序編譯期,java 虛擬機就將常量字符串的 “+” 連接優化為連接后的值。
這樣一來,最終只會在常量池中創建一個 abc 對象,并沒有創建臨時字符串對象 a 和 bc,減輕了垃圾收集器的壓力。s1 == ("a" + "bc"),因為 abc(s1) 在字符串常量池中已經存在了,因此返回值是 true。
2.2 字符串引用重載 "+"
java 虛擬機對于有字符串引用存在的字符串連接,即 s2 + "bc" 在被編譯器執行的時候,會自動引入 StringBuilder 對象,調用其 append() 方法,最終調用 toString() 方法返回其在堆中對象的引用。 下面是反編譯后的部分字節碼。
因此 s2 + "bc" 就等同于下面過程。
s2 + "bc" = new StringBuilder().append(s2).append("bc").toString();s1 == (s2 + "bc") 在進行比較時,s1 是字符串常量池中對象的引用,(s2 + "bc") 則是 java 堆中一個對象的引用,因此返回值是 false。為什么說 s2 + "bc" 返回的是堆中對象的引用呢,只要到 StringBuilder 源碼中查看一下 toString() 就能理解了。
/*** StringBuilder 類的 toSTring() 方法*/@Overridepublic String toString() {// Create a copy, don't share the arrayreturn new String(value, 0, count);}三、參考資料
- String 對象內存分配 (常量池和堆的分配)
- Java—String 字符串運算符"+"重載分析
總結
以上是生活随笔為你收集整理的String 对象内存分配策略的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎么开通信用卡 提前准备好这些一定没错
- 下一篇: static 关键字静态导包