大家都知道字符串频繁的相加是很消耗内存的,今天我没事干做了个试验,发现使用+号并不会影响内存,而使用+=会很消耗内存。
然后查了下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();
}
}
然后查了下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();
}
}
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();
}
}
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)
str+=str+"aa";//立马挂掉
str=str+"aa"; //一直没挂掉
这2个是一样吗?
str+="aa";吧
str+=str;//立马挂掉
str=str+str; //一直没挂掉
这两句是一样的str+=str+"aa";//立马挂掉
str=str+"aa"; //一直没挂掉
这两句显然不一样,上一句是每次把字符串double一下再加2个字符,相当于是n^2+2
下面一个是每次加2个字符,相当于n+2
上面是指数级增长,下面一个是线性增长,显而易见的上面一个会很快挂掉,下面一个要过很久
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有关吗?路过的高手,麻烦给看看~
实际上编译出来两者的效果一样,都是append2^25次方的东西内存先挂掉了,什么方法都一样
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());
}编译器对源代码进行了编译优化
str+=str;//立马挂掉可以这么用吗???
楼主所说
while(true){
count++;
str+=str;//立马挂掉
//str=str+str; //一直没挂掉
}
的//str=str+str; //一直没挂掉怎么可能?就算编译器对str+=str和str=str+str处理不一样,后者也最多坚持多一轮,爆掉的是内存