首頁  >  問答  >  主體

java的string存放位置的疑惑

有一道題目是這樣的:

new String("aaa")建立了幾個物件?答案是創建一個或2個,理由是如果常數區中存在了aaa變量,則只在堆中創建一個;如果常量區不存在aaa變量,則分別在常量區和堆中各創建一個。

但我實際測試的結果卻不符:

String s1 = new String("aaa");
String s2 = "aaa";
System.out.println(s1 == s2); //false

如果說new String("aaa")在堆中和常數區中都創建了對象,那麼為什麼s2不直接復用s1的常數池的引用呢?

補充:
發現自己想錯了,s1應該指向的堆中的元素,而s2指向的是常數池中的,所以兩者不相等是對的,那有沒有辦法測試測試出new String("aaa")也同時在常數池中建立物件了呢?

又或String s3 = "aa".concat("a"); 請問這個s3是指向堆中還是指向常數池的,它能否復用常數池中的變數呢?

仅有的幸福仅有的幸福2713 天前667

全部回覆(6)我來回復

  • 过去多啦不再A梦

    过去多啦不再A梦2017-05-17 10:02:54

        String s1 = new String("aaa");
        String s2 = "aaa";
        System.out.println(s1 == s2); //false
        System.out.println(s1.intern() == s2); //true

    當一個String實例呼叫intern()方法時,會查找常數池中是否有相同的字串常數,如果有,則傳回其的引用,如果沒有,則在常數池中增加一個等於str的字串並傳回它的引用,由於s2已經在常數池中,所以s1.intern()不會再創建,而是直接引用同一個"aaa"。

    如果這樣還不夠明顯,那我們就來試驗,

    public class Cons {
        public static void main(String[] args) throws InterruptedException {
            String s1 = new String("vv");
        }
    }
    

    然後命令列

    注意常量池有 VV

    回覆
    0
  • PHPz

    PHPz2017-05-17 10:02:54

    問題一:

    String a = “aaa”,會在常數池中建立對象,如果常數池中存在同樣的對象,那a就直接指向該對象。而 String a = new String("aaa"),若常數池中存在,則不在常數池中創建,只在堆中創建。

    String a = new String("aaa");
    String b = new String("aaa");
    System.out.println(a == b);//比较两者堆中的引用返回false
    System.out.println(a.intern() == b.intern());//比较两者常量池中的引用,返回true
    

    問題二:

    從原始碼找出答案String s3 = "aa".concat("a"); 其實相當於 String s3 = new String("aaa"),會在堆中建立物件。

    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);
    }
    
    

    回覆
    0
  • 伊谢尔伦

    伊谢尔伦2017-05-17 10:02:54

    String不是每次賦值都會重新建立一個String物件實例嗎?所以才會有StringBuilder呀。

    回覆
    0
  • ringa_lee

    ringa_lee2017-05-17 10:02:54

    按照物件導向的思想,有沒有同時在常數池創建對象,可能String自己最清楚,嗯,他有一個intern()方法。

    回覆
    0
  • 漂亮男人

    漂亮男人2017-05-17 10:02:54

    前面幾位的回答已經非常好了,我補充一句,我們常說的「把字串放到常數池」是指把字串的引用放到字串常數池(String Pool,本質是一個哈希表)中,字串本身還是放在堆上的。

    回覆
    0
  • 过去多啦不再A梦

    过去多啦不再A梦2017-05-17 10:02:54

    雷雷

    回覆
    0
  • 取消回覆