字符串概念的困惑

时间:2013-06-30 18:02:14

标签: java

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 个答案:

答案 0 :(得分: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"实例。要将这两者附加在一起,它会创建一个StringBuilder实例并附加值。之后,它会在该实例上调用toString(),从而在其中创建一个新的String实例,其中包含"JAVAWORLD"

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

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

总结一下:

  • 案例1:三个String个实例:池中有两个,一个在追加后新构造的实例(还创建了一个StringBuilder实例来附加两个字符串,总共产生4个对象。 / LI>
  • 案例2:池中的一个实例。

答案 1 :(得分: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();

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

答案 2 :(得分:0)

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

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

一样

答案 3 :(得分:0)

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

在第二种情况下,如果您正在执行类似

的操作
String str1="JAVA";
String str2="WORLD";
String strTest="JAVA"+"WORLD";

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

但如果您正在做类似

的事情
 String strTest="JAVA"+"WORLD";

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

有关String对象池see here

的更多信息

希望这有帮助。