2016-11-08 45 views
1
String str = "test"; 

str = str + "test2"; 
str = str + "test3"; 
str = str + "test4"; 
str = str + "test5"; 

上面的代码将创建多少个对象,以及有多少对象可用于垃圾回收?将创建多少个对象以及将有多少对象可用于垃圾回收?

有人能解释一下吗?

+2

请参阅http://stackoverflow.com/questions/10443492/how-many-objects-are-created,但该问题已过了几年,可能已过时。 – ajb

+0

查看http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.18.1,似乎没有明确的答案 - 不同的实现可能会有所不同的东西。 – ajb

回答

0

关于字符串操作,JavaC是非常奇怪的。例如,当你做“String + = otherString”时为什么不使用String.concat?

取而代之的是,Java为每行结束的每行创建一个StringBuilder(或StringBuffer,取决于Java版本);你已经连接了字符串。

我把你的代码的测试程序(TCTestWin)和命令行调用:

javap -c TCTestWin.class 

这些结果如下:

0: ldc   #15     // String test 
    2: astore_1 
    3: new   #17     // class java/lang/StringBuilder 
    6: dup 
    7: aload_1 
    8: invokestatic #19     // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String; 
    11: invokespecial #25     // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 
    14: ldc   #28     // String test2 
    16: invokevirtual #30     // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    19: invokevirtual #34     // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 
    22: astore_1 
    23: new   #17     // class java/lang/StringBuilder 
    26: dup 
    27: aload_1 
    28: invokestatic #19     // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String; 
    31: invokespecial #25     // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 
    34: ldc   #38     // String test3 
    36: invokevirtual #30     // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    39: invokevirtual #34     // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 
    42: astore_1 
    43: new   #17     // class java/lang/StringBuilder 
    46: dup 
    47: aload_1 
    48: invokestatic #19     // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String; 
    51: invokespecial #25     // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 
    54: ldc   #40     // String test4 
    56: invokevirtual #30     // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    59: invokevirtual #34     // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 
    62: astore_1 
    63: new   #17     // class java/lang/StringBuilder 
    66: dup 
    67: aload_1 
    68: invokestatic #19     // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String; 
    71: invokespecial #25     // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 
    74: ldc   #42     // String test5 
    76: invokevirtual #30     // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    79: invokevirtual #34     // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 
    82: astore_1 
    83: return 

正如你所看到的,对于每一行,javac的创建一个StringBuilder,追加字符串,并继续。

这样的代码,特别是在循环内部使用时,会冲高垃圾收集器。

有三种更好的方法来做到这一点:

  1. 使用CONCAT代替:

    String str = "test"; 
    str = str.concat("test2"); 
    str = str.concat("test3"); 
    str = str.concat("test4"); 
    str = str.concat("test5"); 
    
  2. 使用串联的单行线,这将创建一个单一的StringBuilder。请记住每个;将创建另一个StringBuilder。请注意,在下面的常量字符串串联中,Java编译器将创建一个字符串。但是,如果添加一个或多个字符串变量,则将创建StringBuilder。

    String str = "test" + "test2" + "test3" + "test4" + "test5"; 
    
  3. 创建一个StringBuilder自己,做串联,并REUSE StringBuilder的。这有最好的表现,特别是当做在循环

    StringBuilder sb = new StringBuilder(512); 
    for (int i = 0; i < 10000; i++) 
    { 
        sb.setLength(0); 
        sb.append("test"); 
        sb.append("test2"); 
        sb.append("test3"); 
        sb.append("test4"); 
        sb.append("test5"); 
        sb.append(i); 
        String s = sb.toString(); 
    } 
    

因此,从上面的代码中,4个不同的StringBuilders将被创建。在最终的String之后,所有的StringBuilders都将被收集。

+1

如果您使用编号或项目符号,则以下代码需要双缩进。 – EJP

+0

它们不使用多个'String.concat()'调用,因为单个'StringBuilder'效率更高。编译器选择比程序员能想到的更好的目标代码没有什么“非常奇怪的”。这就是他们的目的。注意你没有真正回答这个问题。 – EJP

+0

完全同意...如果...创建了一个StringBuilder。但是,发布的代码不会创建单个StringBuilder,而是创建4个! –

0

多少对象将被创建

在运行时,如图4所示,即str四个计算值,但不包括其中来自于常量池的初始值。

以及有多少对象可用于垃圾回收?

在该代码的末尾但在str超出范围之前,三个即str的三个中间值。

请注意,我计数Strings。每个String将有一个关联char[]这是另一个对象。

但是,如果周围的代码使得JVM可以确定str不能在这些代码行之间改变,则它可能分别低至1和0。

+0

我想'String str =“test”;'也会在String常量池中创建一个对象,它位于JVM的堆内存中。所以没有。的对象将是5. –

+0

@RohitGaikwad但在运行时不执行此代码。它发生在课程加载时间。 – EJP