7

创建了多少个 String 对象

我正在为 SCJP 学习,我似乎无法解决这个字符串问题。根据我看待问题的方式,我似乎看到了几个可能的答案。

在下面的初始化中,创建了多少个字符串对象?

String s1 = "A" + "B" + "C" + "D";
System.out.println(s1)

最初我认为 5 个对象,即

"A"
"B"
"C"
"D"
"ABCD"

但是再想一想我不太确定,因为例如编译器会连接"A" + "B"为一个对象吗?即创建 7 个对象?

"A"
"B"
"C"
"D"
"AB"
"ABC"
"ABCD" 

此外,如果将代码更改为

String s1 = new String("A" + "B" + "C" + "D");
System.out.println(s1);

最后怎么样:

String s1 = "A";
String s2 = new String("A");

在上面的例子中,我认为只会创建 2 个对象

object 1 - "A"
object 2 - a String object that refers to the "A" object above.

这是正确的还是它们不相关?即,从常量池引用的对象将不同于 s2 引用所引用的对象。

谢谢

编辑

另外,请注意我有兴趣知道创建的对象总数,包括那些被丢弃的对象,而不仅仅是那些最终进入常量池的对象。

编辑

看着乔恩的回答,我可能完全误解了对象的创建方式。我知道一个字符串在常量池中只创建一次并且它被重用但我不确定构造“最终”字符串时所经历的过程。这是我正在阅读的书中的部分,这似乎表明创建了临时对象,这与这里的答案完全相反。(或者这本书是错的,或者我误解了这本书)

代码示例是

String s1 = "spring ";  
String s2 = s1 + "summer ";  
s1.concat("fall ");  
s2.concat(s1);  
s1 += "winter";  
System.out.println(s1 + " " + s2);

问题是

输出是什么?对于额外的功劳,在 println 语句之前创建了多少个 String 对象和多少个引用变量。

而答案

此代码片段的结果是spring water spring summer. 有两个参考变量,s1 和 s2。一共创建了八个String对象,分别为“spring”、“summer”(丢失)、“spring summer”、“falls”(丢失)、“spring fall”(丢失)、“spring summer spring”(丢失) ,“冬天”(丢失),“春天冬天”(此时“春天”丢失)。八个String对象中只有两个在这个过程中没有丢失

谢谢

4

3 回答 3

13

编译器会将整个“A”+“B”+“C”+“D”连接成一个常量 - 所以在你的第一个例子中,最终只创建了一个字符串。如果您多次执行相同的代码,将重复使用相同的字符串。常量放在类文件中,当类加载时,VM 检查字符串池中是否已经存在相等的字符串 - 因此即使您在多个类中有相同的代码,它也会重用它。

您可以使用以下方法验证类中的常量池中只有一个字符串javap

javap -v Test

Constant pool:
   #1 = Methodref   #6.#17     //  java/lang/Object."<init>":()V
   #2 = String      #18        //  ABCD
   #3 = Fieldref    #19.#20    //  java/lang/System.out:Ljava/io/PrintStream;

但是,这里:

String s1 = "A";
String s2 = new String("A");

你最终会得到两个单独的字符串对象。每次执行代码时都会重用一个(常量)(并在两个语句之间共享),并且由于每次调用构造函数都会创建一个新的。

例如,这个方法:

public static void foo() {
    for (int i = 0; i < 5; i++) {
        String s1 = "A";
        String s2 = new String("A");
    }
}

...最终将使用六个字符串对象 - 一个用于常量,每次调用该方法时都会创建五个新对象。

于 2011-11-29T19:44:51.557 回答
4

创建了多少对象?

String s1 = "A" + "B" + "C" + "D";
System.out.println(s1)

一个或一个都没有。这简化为一个可以已经加载的字符串文字。

String s1 = new String("A" + "B" + "C" + "D");
System.out.println(s1);

这总是会创建一个额外的对象。

顺便说一句:字符串通常由两个对象组成, theStringchar[]it 包装。

于 2011-11-29T19:49:16.270 回答
2
String s1 = "A" + "B" + "C" + "D";

编译器将只创建一个字符串文字“ABCD”并将其放入字符串池中。将创建一个对象(字符串池中的那个)。


String s1 = new String("A" + "B" + "C" + "D");

此处相同,只是您从字符串文字中复制它。因此,将在此处创建 2 个对象。一个接new一个在字符串池中。


String s1 = "A";
String s2 = new String("A");

同样在这里,"A"将是字符串池中的一个常量。构造函数将复制它。所以这里将创建两个对象。

于 2011-11-29T19:44:08.753 回答