0
class StringTest1
{
public static final void main(String... a)
{
    String str1="JAVA";
    String str2="WORLD";

    String str3=str1+str2;
}
}

在这个过程中会创建多少个对象?我认为将创建 3 个对象。

class StringTest2
{
public static final void main(String... a)
{

    String strTest="JAVA"+"WORLD";
}
}

在这个过程中会创建多少对象?有多少对象可以访问?有人告诉我“JAVA”+“WORLD”是一个表达式,它不会存储在字符串池中。

4

4 回答 4

5

在第一个示例中,您将得到三个String对象。您实际上可以在字节码中看到这一点。

假设您有以下代码:

public class StrTest {
    public static void main(String[] args) {
        String str1 = "JAVA";
        String str2 = "WORLD";

        String str3 = str1 + str2;

        String strTest = "JAVA" + "WORLD";
    }
}

生成的字节码是:

public class StrTest {
  public StrTest();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return        

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String JAVA
       2: astore_1      
       3: ldc           #3                  // String WORLD
       5: astore_2      
       6: new           #4                  // class java/lang/StringBuilder
       9: dup           
      10: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V
      13: aload_1       
      14: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      17: aload_2       
      18: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      21: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      24: astore_3      
      25: ldc           #8                  // String JAVAWORLD
      27: astore        4
      29: return        
}

您可以看到 Java 编译器在字符串池中创建了两个实例String。要将这两个附加在一起,它创建了一个实例并附加了值。之后,它调用该实例,该实例在其中创建一个新实例。"JAVA""WORLD"StringBuildertoString()String"JAVAWORLD"

在第二种情况下,您只会得到一个String实例,因为 Java 编译器足够聪明,可以看到您基本上拥有的是一个常量,因此它通过评估该表达式并在字符串中创建一个 String实例来执行一些编译时优化包含"JAVAWORLD". 然后将该实例的引用分配给strTest

关于字符串"JAVA""WORLD""JAVAWORLD",这些基本上是实习字符串。由于字符串在 Java 中是不可变的,因此您只需要一个对唯一实例的引用,该实例可以在代码中的多个位置重用。这基本上是一种节省内存的方法。

所以总结一下:

  • 案例1:三个String实例:池中的两个,追加后新构造的一个(StringBuilder还创建了一个实例来追加两个字符串,总共有4个对象)。
  • 案例 2:池中的一个实例。
于 2013-06-30T18:16:48.823 回答
1
String str1="JAVA";
String str2="WORLD";

String strTest="JAVA"+"WORLD";

三行中的每一行都将创建一个 String 对象。但是,如果代码多次生成,它将始终是同一个对象。此外,每个 String 对象都将包含一个char[]对象,因此从技术上讲,它是每行 2 个对象。


String str3=str1+str2;

假设这不能由 优化javac,它将编译为

String str3 = new StringBuilder(str1).append(str2).toString();

因此,它不仅会创建一个字符串,还会创建一个在代码中无法访问的 StringBuilder。因此,在最坏的情况下,会创建 4 个对象:String、StringBuilder 和 to char 数组(因为它必须在 期间调整大小append

于 2013-06-30T18:17:46.543 回答
0

在第一种情况下,编译器无法确定哪些值将具有str1str2因此它不是一个常量表达式,因此它将在运行时进行评估。将有三个对象(两个来自字符串文字,一个作为其连接创建)。

在第二种情况下,编译器能够计算结果,所以只有一个对象,就像你写的一样"JAVAWORLD"

于 2013-06-30T18:09:36.800 回答
0

在第一种情况下,将创建三个对象,并且所有这些对象都可以访问,因为您拥有对它们的实时引用。

在第二种情况下,如果你正在做类似的事情

String str1="JAVA";
String str2="WORLD";
String strTest="JAVA"+"WORLD";

然后将创建三个对象。在您创建 strTest 时,此处“JAVA”将位于字符串对象池中,因此它不会为此分配内存,而是直接从池中引用。“世界”也是如此。然后将从这两个对象中创建一个新对象,并将其分配给 strTest。这里的可访问对象将是 3。

但是如果你正在做类似的事情

 String strTest="JAVA"+"WORLD";

这里只有一个对象可供您访问,即“JAVAWORLD”。池中有对“JAVA”和“WORLD”的引用,但您无法直接访问它们。正如@Vivin Paliath 提到的那样,“JAVA”和“WORLD”将被实习以形成一个新的对象“JAVAWORLD”。因此,只创建了两个对象。

有关字符串对象池的更多信息,请参见此处

希望这可以帮助。

于 2013-06-30T18:10:50.727 回答