麻烦先看看我整理的笔记,问题在后面,如果笔记有错请前辈们一定指出来,谢谢了!======================================================================
String str1 = "a";
String str2 = "b";
String str3 = str1 + str2;
======================================================================
这里str3的赋值过程不是表面上看起来的那么简单。我们来看看它的字节码:
======================================================================
   L2 (6)
    LINENUMBER 9 L2
    NEW java/lang/StringBuilder
    DUP
    ALOAD 1
    INVOKESTATIC java/lang/String.valueOf(Ljava/lang/Object;)Ljava/lang/String;
    INVOKESPECIAL java/lang/StringBuilder.<init>(Ljava/lang/String;)V
    ALOAD 2
    INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
    INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String;
    ASTORE 3
======================================================================
先构造一个StringBuilder对象(这是在1.5以及之后版本的jdk上解释后的字节码,jdk1.4构造的是StringBuffer对象),然后通过引用str1取出对应的值“a”为字符串类型,作为参数来构造这个StringBuilder,接着调用StringBuilder的append方法,以引用str2对应的值“b”为参数来追加字符串,最后调用它的toString转化为String类型保存。(jvm的指令我不是很懂,说得不妥当或者有欠缺的地方请一定指出来,谢谢!)如果两个字符串变量相加的操作很频繁,每次操作都要创建一个StringBuilder,并且将它转化为String类型,之后不用的对象又需要GC来回收,会耗费很多的资源。而如果用以下方法:
======================================================================
StringBuilder str4 = new StringBuilder();
str4.append(str1);
str4.append(str2);
======================================================================
我们先来看看它的字节码:
======================================================================
   L4 (20)
    LINENUMBER 13 L4
    NEW java/lang/StringBuilder
    DUP
    INVOKESPECIAL java/lang/StringBuilder.<init>()V
    ASTORE 4
   L5 (25)
    LINENUMBER 14 L5
    ALOAD 4
    ALOAD 1
    INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
    POP
   L6 (30)
    LINENUMBER 15 L6
    ALOAD 4
    ALOAD 2
    INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
    POP
======================================================================
看起来似乎比上面的那种方法操作更麻烦。但仔细看看,用这第二种方法追加字符串,无论加多少次,都只需要在一开始创建一个StringBuilder对象,而且不用调用toString方法,只有在需要取值的时候,人为地去调用它的toString方法。
现在问题来了:
按这么说的话, 用+和用append的区别也只有在对单个string进行不断的追加的时候才会很明显吧。
如果每次的追加操作都是对不同的string呢?是不是两者几乎没有区别?而我又做了以下试验:public class Test {
public static void main(String[] args)
{
String[] strArray1 = new String[500000];
String[] strArray2 = new String[500000];

String str1 = "a";

long beginTime = System.currentTimeMillis();

for(int i = 0;i<strArray1.length;i++)
{
strArray1[i]=str1+str1;
}

long endTime = System.currentTimeMillis();

System.out.println("+ operation took "+(endTime-beginTime)/1000.0+" seconds");

beginTime = System.currentTimeMillis();

for(int i = 0;i<strArray2.length;i++)
{
StringBuilder strBuilder = new StringBuilder();
strBuilder.append(str1);
strBuilder.append(str1);
strArray2[i]=strBuilder.toString();
}

endTime = System.currentTimeMillis();

System.out.println("+ operation took "+(endTime-beginTime)/1000.0+" seconds");
}
}
发现就算每次追加的操作都是对不同的string进行,append比+的速度快一倍,百思不得其解。请前辈们指点。

解决方案 »

  1.   

    啊哦,代码错了,后面那个输出应该是,呵呵,没什么影响,一时大意了,不好意思。System.out.println("append method took "+(endTime-beginTime)/1000.0+" seconds");
      

  2.   

    啊哦,代码错了,后面那个输出应该是System.out.println("append method took "+(endTime-beginTime)/1000.0+" seconds");呵呵,没什么影响,一时大意了,不好意思。
      

  3.   


    发现就算每次追加的操作都是对不同的string进行,append比+的速度快一倍,百思不得其解。请前辈们指点。
    MS +的话你在内存中间要重新开辟一个内存,再进行写道缓冲区末端。这里要耗费时间。
    append 方法始终将这些字符添加到缓冲区的末端;省了开辟内存的时间
      

  4.   

    String 每次都要创建一个空间,而StringBuffer只创建一次.
      

  5.   

    to mx1029():你说的对最后那段代码不适用吧?
    for(int i = 0;i<strArray2.length;i++)
    {
    StringBuilder strBuilder = new StringBuilder();
    strBuilder.append(str1);
    strBuilder.append(str1);
    strArray2[i]=strBuilder.toString();
    }
    这不也是每次都创建一个空间么?
      

  6.   

    + operation took 0.515 seconds
    + append method took 0.516 seconds
    那里速度快了
      

  7.   

    + operation took 0.531 seconds
    append operation took 0.359 seconds
      

  8.   

    String是"轻量级"的,相对于string,StringBuilder是"超重量级"的.....这么说不明白的话你可以定义大量的相同数量的StringBuilder和String,(一定要每个都给个引用,也就是说不让它自动回收),你看下内存的空间和时间就知道了
      

  9.   

    那不就是把代码里的String[] strArray2 = new String[500000];改成StringBuilder[] strArray2 = new StringBuilder[500000];把strArray2[i]=strBuilder.toString();改成strArray2[i]=strBuilder;么??改了之后结果是:+ operation took 0.531 seconds
    append operation took 0.297 seconds
      

  10.   

    + operation took 0.75 seconds
    + operation took 0.734 seconds基本一样
      

  11.   

    难道是我机器的问题??->http://topic.csdn.net/u/20070627/16/80f6e928-64f2-4a7f-97f0-c2c86372951f.html再测试看看
      

  12.   

    我的是这个结果:+ operation took 0.531 seconds
    + operation took 0.484 seconds
      

  13.   

    我的一个朋友PD805双核cpu测试结果:
    + operation took 0.485 seconds
    append method took 0.484 seconds
    我的是AMD 3800+:
    + operation took 0.516 seconds
    append method took 0.375 seconds
    怪怪怪怪..我的配置:
    AMD 速龙 3800+ (双核)
    内存 512X2=1GB DDR2 667 (双通道)