大家都知道字符串频繁的相加是很消耗内存的,今天我没事干做了个试验,发现使用+号并不会影响内存,而使用+=会很消耗内存。
然后查了下jdk1.6的api,说明如下:
Java 语言提供对字符串串联符号("+")以及将其他对象转换为字符串的特殊支持。字符串串联是通过 StringBuilder(或 StringBuffer)类及其 append 方法实现的。但是+=依旧很消耗内存,循环二十多次就挂掉了,那么在字符串相加时采用"+"和"+="到底区别在哪?以下是我做试验的例子
public static void main(String[] args) {

String str = "str_";
int count = 0;
try {
while(true){
count++;
str+=str;//立马挂掉
                                     //str=str+str; //一直没挂掉
}
} catch (Error e) {
System.out.println(count);
e.printStackTrace();
}


}

解决方案 »

  1.   

    恩 刚才那个 确实是两个都挂掉了 你试试这个
    public static void main(String[] args) { String str = "str_";
    int count = 0;
    try {
    while(true){
    count++;
    // str+=str+"aa";//立马挂掉
      str=str+"aa"; //一直没挂掉
    }
    } catch (Error e) {
    System.out.println(count);
    e.printStackTrace();
    }
    }
      

  2.   

    和编译器优化无关,使用+=的时候 count输出为20多次
      

  3.   

    // str+=str+"aa";//立马挂掉 //这个跟下面不一样,要跟下面一样,应该是str+="aa"; 这样也不挂
    str=str+"aa"; //一直没挂掉用javap -c xx查看一下编译代码,发现两种一样
    str+="aa"时
    class XX extends java.lang.Object{
    XX();
      Code:
       0:   aload_0
       1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
       4:   returnpublic static void main(java.lang.String[]);
      Code:
       0:   ldc     #2; //String str_
       2:   astore_1
       3:   iconst_0
       4:   istore_2
       5:   iinc    2, 1
       8:   new     #3; //class java/lang/StringBuilder
       11:  dup
       12:  invokespecial   #4; //Method java/lang/StringBuilder."<init>":()V
       15:  aload_1
       16:  invokevirtual   #5; //Method java/lang/StringBuilder.append:(Ljava/lang
    String;)Ljava/lang/StringBuilder;
       19:  ldc     #6; //String aa
       21:  invokevirtual   #5; //Method java/lang/StringBuilder.append:(Ljava/lang
    String;)Ljava/lang/StringBuilder;
       24:  invokevirtual   #7; //Method java/lang/StringBuilder.toString:()Ljava/l
    ng/String;
       27:  astore_1
       28:  goto    5
       31:  astore_3
       32:  getstatic       #9; //Field java/lang/System.out:Ljava/io/PrintStream;
       35:  iload_2
       36:  invokevirtual   #10; //Method java/io/PrintStream.println:(I)V
       39:  aload_3
       40:  invokevirtual   #11; //Method java/lang/Error.printStackTrace:()V
       43:  return
      Exception table:
       from   to  target type
         5    31    31   Class java/lang/Error
    }str=str+"aa"时
    class XX extends java.lang.Object{
    XX();
      Code:
       0:   aload_0
       1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
       4:   returnpublic static void main(java.lang.String[]);
      Code:
       0:   ldc     #2; //String str_
       2:   astore_1
       3:   iconst_0
       4:   istore_2
       5:   iinc    2, 1
       8:   new     #3; //class java/lang/StringBuilder
       11:  dup
       12:  invokespecial   #4; //Method java/lang/StringBuilder."<init>":()V
       15:  aload_1
       16:  invokevirtual   #5; //Method java/lang/StringBuilder.append:(Ljava/lang
    String;)Ljava/lang/StringBuilder;
       19:  ldc     #6; //String aa
       21:  invokevirtual   #5; //Method java/lang/StringBuilder.append:(Ljava/lang
    String;)Ljava/lang/StringBuilder;
       24:  invokevirtual   #7; //Method java/lang/StringBuilder.toString:()Ljava/l
    ng/String;
       27:  astore_1
       28:  goto    5
       31:  astore_3
       32:  getstatic       #9; //Field java/lang/System.out:Ljava/io/PrintStream;
       35:  iload_2
       36:  invokevirtual   #10; //Method java/io/PrintStream.println:(I)V
       39:  aload_3
       40:  invokevirtual   #11; //Method java/lang/Error.printStackTrace:()V
       43:  return
      Exception table:
       from   to  target type
         5    31    31   Class java/lang/Error
    }从编译代码来看,效率应该是一样的(个人感觉,没再深入考证),不过+=存在隐形转换,也就是自动保持和+=左边一致的类型,而+要自己保证=右边的类型要和=左边的类型一致,LZ可以改成byte试试 byte b = 0; b+=1 or b=(byte)(b+1)
      

  4.   

    楼主,你没明白+=和+的区别吧?
    str+=str+"aa";//立马挂掉
    str=str+"aa"; //一直没挂掉
    这2个是一样吗?
    str+="aa";吧 
      

  5.   

    这个问题还需要反编译吗?
    str+=str;//立马挂掉
    str=str+str; //一直没挂掉
    这两句是一样的str+=str+"aa";//立马挂掉
    str=str+"aa"; //一直没挂掉
    这两句显然不一样,上一句是每次把字符串double一下再加2个字符,相当于是n^2+2
    下面一个是每次加2个字符,相当于n+2
    上面是指数级增长,下面一个是线性增长,显而易见的上面一个会很快挂掉,下面一个要过很久
      

  6.   

    发现一个更有意思的问题,源代码如下public class TestPlus {
    public static void main(String[] args) {
    String str = "_ok_";
    int count = 0;
    try {
    while (true) {
    count++;
    str += str;// 情况1
    // str = str + str; //情况2
    System.out.println(str); //输出语句
    }
    } catch (Error e) {
    System.out.println(count);
    e.printStackTrace();
    } System.out.println("No:" + count);
    }
    }
    当情况1和情况2分别不加输出语句时,情况1执行22次异常终止,情况2循环执行当情况1和情况2分别加输出语句时,情况和情况2循环执行问题:什么原因导致如此差异?猜想:难道是String常量池和I/O有关吗?路过的高手,麻烦给看看~
      

  7.   

    经测试都是24的时候挂掉
    实际上编译出来两者的效果一样,都是append2^25次方的东西内存先挂掉了,什么方法都一样
      

  8.   

    找个反编译工具,把两种写法编译出来的 class 文件全部都反编译一次
    String str = "text abcdefg a";
    int cnt = 0;
    try{
    while(true){
    cnt++;
    //str += str;
    str = str + str;
    }
    }catch(Error e){
    e.printStackTrace();
    System.out.println("次数: " + cnt);
    }
    两种写法反编译之后都变成了:String string = "text abcdefg a";
    int i = 0;
    try {
        for (;;) {
    i++;
    string = new StringBuilder().append(string).append(string)
         .toString();
        }
    } catch (Error error) {
        error.printStackTrace();
        System.out.println(new StringBuilder().append("\u6b21\u6570: ")
       .append
       (i).toString());
    }编译器对源代码进行了编译优化
      

  9.   

    因为每个人的编译环境不一样,包括JDK版本等因素的制约,编译后的目标文件可能会不一样.我还是认为是编译器优化的原因
      

  10.   

    字符串可以那么 
     str+=str;//立马挂掉可以这么用吗???
      

  11.   

    同意。
    楼主所说
    while(true){
    count++;
    str+=str;//立马挂掉
      //str=str+str; //一直没挂掉
    }
    的//str=str+str; //一直没挂掉怎么可能?就算编译器对str+=str和str=str+str处理不一样,后者也最多坚持多一轮,爆掉的是内存