java的string存放位置的疑惑
問題描述
有一道題是這樣的:
new String('aaa')創(chuàng)建了幾個(gè)對象? 答案是創(chuàng)建一個(gè)或2個(gè),理由是如果常量區(qū)中存在了aaa變量,則只在堆中創(chuàng)建一個(gè);如果常量區(qū)不存在aaa變量,則分別在常量區(qū)和堆中各創(chuàng)建一個(gè)。
但我實(shí)際測試的結(jié)果卻不符:
String s1 = new String('aaa');String s2 = 'aaa';System.out.println(s1 == s2); //false
如果說new String('aaa')在堆中和常量區(qū)中都創(chuàng)建了對象,那么為什么s2不直接復(fù)用s1的常量池的引用呢?
補(bǔ)充:發(fā)現(xiàn)自己想錯(cuò)了,s1應(yīng)該指向的堆中的元素,而s2指向的是常量池中的,所以兩者不相等是對的,那有沒有辦法測試測試出new String('aaa')也同時(shí)在常量池中創(chuàng)建對象了呢?
又或者String s3 = 'aa'.concat('a'); 請問這個(gè)s3是指向堆中還是指向常量池的,它能否復(fù)用常量池中的變量呢?
問題解答
回答1:String s1 = new String('aaa'); String s2 = 'aaa'; System.out.println(s1 == s2); //false System.out.println(s1.intern() == s2); //true
當(dāng)一個(gè)String實(shí)例調(diào)用intern()方法時(shí),會(huì)查找常量池中是否有相同的字符串常量,如果有,則返回其的引用,如果沒有,則在常量池中增加一個(gè)等于str的字符串并返回它的引用,由于s2已經(jīng)在常量池中,所以s1.intern()不會(huì)再創(chuàng)建,而是直接引用同一個(gè)'aaa'。
如果這個(gè)還不夠明顯,那么我們就來試驗(yàn),
public class Cons { public static void main(String[] args) throws InterruptedException {String s1 = new String('vv'); }}
然后命令行
注意常量池有 VV
回答2:問題一:String a = “aaa”,會(huì)在常量池中創(chuàng)建對象,如果常量池中存在同樣的對象,那a就直接指向該對象。而 String a = new String('aaa'),若常量池中存在,則不在常量池中創(chuàng)建,只在堆中創(chuàng)建。
String a = new String('aaa');String b = new String('aaa');System.out.println(a == b);//比較兩者堆中的引用返回falseSystem.out.println(a.intern() == b.intern());//比較兩者常量池中的引用,返回true問題二:
從源碼中找答案String s3 = 'aa'.concat('a'); 其實(shí)就相當(dāng)于 String s3 = new String('aaa'),會(huì)在堆中創(chuàng)建對象。
public String concat(String str) { int otherLen = str.length(); if (otherLen == 0) {return this; } int len = value.length; char buf[] = Arrays.copyOf(value, len + otherLen); str.getChars(buf, len); return new String(buf, true);}回答3:
String不是每次賦值都重新創(chuàng)建一個(gè)String對象實(shí)例嗎?所以才會(huì)有StringBuilder呀。
回答4:按照面向?qū)ο蟮乃枷耄袥]有同時(shí)在常量池創(chuàng)建對象,可能String自己最清楚,嗯,他有一個(gè)intern()方法。
回答5:前面幾位的回答已經(jīng)非常好了,我補(bǔ)充一句,我們經(jīng)常說的“把字符串放到常量池”是指把字符串的引用放到字符串常量池(String Pool,本質(zhì)是一個(gè)哈希表)中,字符串本身還是放在堆上的。
回答6:// new一次就是在堆中創(chuàng)建一個(gè)新的對象。不new的話aaa直接在字符串常量中取值;// String s2 = 'aaa'; 先在內(nèi)存中尋找aaa,如果有,則將aaa的內(nèi)存首地址指向了s1, 如果沒有則在堆中中創(chuàng)建一個(gè)新的對象。// String s1 = new String('aaa');// // 不管'aaa'在內(nèi)存中是否存在,都會(huì)在堆中開辟新空間,將字符串'aaa'的內(nèi)存首地址指向s1。String a = 'aaa';// aaa在常量池中創(chuàng)建一個(gè)對象,將內(nèi)存首地址指向了aString b = 'aaa';// 直接aaa已經(jīng)存在的內(nèi)存首地址指向b。String c = new String('aaa');// 不管存在與否,在堆中創(chuàng)建1個(gè)空間,內(nèi)存首地址與常量池中的地址完全不同System.out.println(a==b);// trueSystem.out.println(a==c);// false
相關(guān)文章:
1. mysql - 數(shù)據(jù)庫建字段,默認(rèn)值空和empty string有什么區(qū)別 1102. 新人求教MySQL關(guān)于判斷后拼接條件進(jìn)行查詢的sql語句3. 在mybatis使用mysql的ON DUPLICATE KEY UPDATE語法實(shí)現(xiàn)存在即更新應(yīng)該使用哪個(gè)標(biāo)簽?4. mysql - 這種分級一對多,且分級不平衡的模型該怎么設(shè)計(jì)表?5. Navicat for mysql 中以json格式儲(chǔ)存的數(shù)據(jù)存在大量反斜杠,如何去除?6. mysql - 數(shù)據(jù)庫表中,兩個(gè)表互為外鍵參考如何解決7. php - 公眾號文章底部的小程序二維碼如何統(tǒng)計(jì)?8. mysql - 表名稱前綴到底有啥用?9. mysql - 千萬數(shù)據(jù) 分頁,當(dāng)偏移量 原來越大時(shí),怎么優(yōu)化速度10. mac OSX10.12.4 (16E195)下Mysql 5.7.18找不到配置文件my.cnf
