Zweifel am Speicherort von Java-Strings
仅有的幸福
仅有的幸福 2017-05-17 10:00:54
0
6
691

Es gibt eine Frage wie diese:

Wie viele Objekte werden durch new String("aaa") erstellt? Die Antwort ist, eine oder zwei zu erstellen. Der Grund dafür ist, dass, wenn die aaa-Variable im Konstantenbereich vorhanden ist, nur eine im Heap erstellt wird. Wenn die aaa-Variable nicht im Konstantenbereich vorhanden ist, wird eine im Konstantenbereich erstellt und einer auf dem Haufen.

Aber die Ergebnisse meines tatsächlichen Tests sind inkonsistent:

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

Wenn new String("aaa") Objekte sowohl im Heap als auch im Konstantenbereich erstellt, warum verwendet s2 dann nicht direkt den Verweis auf den Konstantenpool von s1 wieder?

Ergänzung:
Ich habe fälschlicherweise gedacht, dass s1 auf das Element im Heap zeigen sollte und s2 auf das Element im Konstantenpool zeigen sollte. Es ist also richtig, dass die beiden nicht gleich sind new String("aaa") erstellt gleichzeitig auch Objekte im Konstantenpool?

Oder String s3 = "aa".concat("a"); Zeigt dieser s3 auf den Heap oder den Konstantenpool? Kann er Variablen im Konstantenpool wiederverwenden?

仅有的幸福
仅有的幸福

Antworte allen(6)
过去多啦不再A梦
    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

PHPzhong

问题一:

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

伊谢尔伦

String不是每次赋值都重新创建一个String对象实例吗?所以才会有StringBuilder呀。

左手右手慢动作

按照面向对象的思想,有没有同时在常量池创建对象,可能String自己最清楚,嗯,他有一个intern()方法。

漂亮男人

前面几位的回答已经非常好了,我补充一句,我们经常说的“把字符串放到常量池”是指把字符串的引用放到字符串常量池(String Pool,本质是一个哈希表)中,字符串本身还是放在堆上的。

过去多啦不再A梦
//    new一次就是在堆中创建一个新的对象。不new的话aaa直接在字符串常量中取值;
//    String s2 = "aaa"; 先在内存中寻找aaa,如果有,则将aaa的内存首地址指向了s1,
      如果没有则在堆中中创建一个新的对象。

//    String s1 = new String("aaa");//  
//    不管"aaa"在内存中是否存在,都会在堆中开辟新空间,将字符串"aaa"的内存首地址指向s1。


String a = "aaa";//   aaa在常量池中创建一个对象,将内存首地址指向了a
String b = "aaa";//    直接aaa已经存在的内存首地址指向b。
String c = new String("aaa");// 不管存在与否,在堆中创建1个空间,内存首地址与常量池中的地址完全不同
System.out.println(a==b);// true
System.out.println(a==c);// false
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage