java 加和加等于的区别是什么

wangxpengx 2010-12-01 12:00:10
大家都知道字符串频繁的相加是很消耗内存的,今天我没事干做了个试验,发现使用+号并不会影响内存,而使用+=会很消耗内存。
然后查了下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();
}


}
...全文
883 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
lxy15329 2010-12-02
  • 打赏
  • 举报
回复
好神奇,以后可得注意点了
javagongcheng 2010-12-02
  • 打赏
  • 举报
回复
挖 好高深!~~
eggno8 2010-12-02
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 zrzlj 的回复:]

这个问题还需要反编译吗?
str+=str;//立马挂掉
str=str+str; //一直没挂掉
这两句是一样的

str+=str+"aa";//立马挂掉
str=str+"aa"; //一直没挂掉
这两句显然不一样,上一句是每次把字符串double一下再加2个字符,相当于是n^2+2
下面一个是每次加2个字符,相当于n+2
上面是指数级增长,下面一个是线性增长,显而易见的……
[/Quote]
同意。
楼主所说
while(true){
count++;
str+=str;//立马挂掉
//str=str+str; //一直没挂掉
}
的//str=str+str; //一直没挂掉怎么可能?就算编译器对str+=str和str=str+str处理不一样,后者也最多坚持多一轮,爆掉的是内存
congcongking 2010-12-02
  • 打赏
  • 举报
回复
我只执行了14次就挂掉了。这是怎么回事啊?
wangxpengx 2010-12-01
  • 打赏
  • 举报
回复
和编译器优化无关,使用+=的时候 count输出为20多次
liufeng0209 2010-12-01
  • 打赏
  • 举报
回复
编译器优化问题吧
wangxpengx 2010-12-01
  • 打赏
  • 举报
回复
恩 刚才那个 确实是两个都挂掉了 你试试这个
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();
}


}
hbgzg3006 2010-12-01
  • 打赏
  • 举报
回复
我这里都挂掉了的。
Forrest0579 2010-12-01
  • 打赏
  • 举报
回复
好神奇...不懂啊
桐桐-Dragon 2010-12-01
  • 打赏
  • 举报
回复
字符串可以那么
str+=str;//立马挂掉

可以这么用吗???
liufeng0209 2010-12-01
  • 打赏
  • 举报
回复
因为每个人的编译环境不一样,包括JDK版本等因素的制约,编译后的目标文件可能会不一样.我还是认为是编译器优化的原因
  • 打赏
  • 举报
回复
暈 我這兩個都掛。。。
小灰狼 2010-12-01
  • 打赏
  • 举报
回复
找个反编译工具,把两种写法编译出来的 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());
}



编译器对源代码进行了编译优化
zdjray 2010-12-01
  • 打赏
  • 举报
回复
经测试都是24的时候挂掉
实际上编译出来两者的效果一样,都是append

2^25次方的东西内存先挂掉了,什么方法都一样
小龙在线 2010-12-01
  • 打赏
  • 举报
回复
发现一个更有意思的问题,源代码如下

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有关吗?

路过的高手,麻烦给看看~
  • 打赏
  • 举报
回复
这个问题还需要反编译吗?
str+=str;//立马挂掉
str=str+str; //一直没挂掉
这两句是一样的

str+=str+"aa";//立马挂掉
str=str+"aa"; //一直没挂掉
这两句显然不一样,上一句是每次把字符串double一下再加2个字符,相当于是n^2+2
下面一个是每次加2个字符,相当于n+2
上面是指数级增长,下面一个是线性增长,显而易见的上面一个会很快挂掉,下面一个要过很久
tom_66 2010-12-01
  • 打赏
  • 举报
回复
应该是一样的效果把
e_forrest 2010-12-01
  • 打赏
  • 举报
回复
同意楼上的。。。
gesanri 2010-12-01
  • 打赏
  • 举报
回复
楼主,你没明白+=和+的区别吧?
str+=str+"aa";//立马挂掉
str=str+"aa"; //一直没挂掉
这2个是一样吗?
str+="aa";吧
qybao 2010-12-01
  • 打赏
  • 举报
回复
// 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: return

public 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: return

public 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)


加载更多回复(1)

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧