日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

String 对象内存分配策略

發布時間:2024/9/30 编程问答 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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 对象内存分配策略的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。