Java解惑之String的"+"一定差于StringBuilder的append吗?
2012-09-25 16:30
323 查看
1)代码:
2)结论:性能上s2 > s3 > s1
3)分析:
Javap查看字节码:
由上图可知:
s1方法:3次创建StringBuilder对象,6次调用append方法添加字符串,3次调用toString方法把添加后的结果返回给result,三者之中,性能最差。
s2方法:编译器对“+”进行优化,合并"A"+"B"+"C"为“ABC”,直接赋给result,三者之中,性能最好。
s3方法:1次创建StringBuilder对象,3次调用append方法添加字符串,1次调用toString方法把添加后的结果返回给result,三者之中,性能居中。
4)总结:
在做字符串的连接操作时,append方法未必是最好的。
等号右侧有变量参与的字符串“+”操作(例如:result += "A"),jvm在做连接时,是创建一个新的StringBuilder对象,然后使用其append方法来实现连接,等号右侧没有变量参与的字符串“+”操作(例如:result = "A" + "B" + "C"),jvm在做连接时,会对右侧的连接操作进行优化,将其合并成一个字符串,然后赋给左边的变量,此时就变成了一次简单的赋值过程。
5)补充
5.1)代码:
5.2)分析:
Javap查看字节码:
由上图可知:
s4方法:1次创建StringBuilder对象,3次调用append方法添加字符串(A和D各占一次),1次调用toString方法把添加后的结果返回给result。
s5方法:1次创建StringBuilder对象,2次调用append方法添加字符串(A和D经优化变成AD,所以A和D加起来仅占一次),1次调用toString方法把添加后的结果返回给result。
5.3)总结:
s4和s5中等号右侧都有变量参于进行字符串的“+”操作(result),所以都会创建StringBuilder对象,并使用其append方法实现连接。
s4中使用的是“=”,所以等号右侧显式的指出了result变量参与字符串的“+”操作,在这种情况下,A和D分两次append完成,而s5中使用的是“+=”,所以等号右侧隐式的指出了result变量参与字符串的“+”操作,在这种情况下,A、D合并成AD,一次append完成。
6)扩展
为什么你会觉得StringBuilder(或StringBuffer)内存占用少呢?
我是这样考虑的:
(1)我们最终想要的是什么?
我们最终想要是一个字符串,用更加准确一点的语言来说,我们最终想要是在堆上开辟一块内存,在该内存中放入我们想要的字符串,然后把该内存的起始地址返回并放入我们的变量中,以使我们持有对该内存的引用。
(2)StringBuilder(或StringBuffer)的作用是什么?
StringBuilder的作用是为了帮住我们完成上面的操作。
(3)为什么要用StringBuilder来完成?
因为String对象是不可变的,如果要想对现有的String对象做修改,我们必须借助StringBuilder这一中间对象,不管我们是自己创建一个StringBuilder还是jvm帮我们创建。
(4)通过StringBuilder我们怎样才能得到我们想要的字符串?
通过调用StringBuilder的toString方法来返回我们的字符串,确切的说应该是返回StringBuilder帮我们维护的堆上一块内存的引用,在该内存中StringBuilder已经把我们想要的字符串放到里面了。
(5)调用完StringBuilder的toString之后,StringBuilder会怎样?
StringBuilder会消亡,因为它的生命周期已经结束。
(6)那我们最终得到的是什么?
我们最终得到的就是我们想要的,即:堆上分配的一块存放我们最终想要字符串的内存,并且这块内存的起始地址已经放到了我们的变量中,我们已经持有了对该内存的引用。
通过上面的分析我们可以看到,StringBuilder只是一个中间态,它的作用只是帮助我们完成我们想要的操作,达到目的,StringBuilder便会消亡,但这个中间态的出现必然会占用内存(例如它的类的加载,它的实例对象的创建),如果我们可以避开这个中间态(上面的s2方法中说的那种情况),那性能自然就会提高,虽然我没试过。
public static String s1() { String result = ""; result += "A"; result += "B"; result += "C"; return result; } public static String s2() { String result = ""; result = "A" + "B" + "C"; return result; } public static String s3() { StringBuilder result = new StringBuilder(); result.append("A").append("B").append("C"); return result.toString(); }
2)结论:性能上s2 > s3 > s1
3)分析:
Javap查看字节码:
由上图可知:
s1方法:3次创建StringBuilder对象,6次调用append方法添加字符串,3次调用toString方法把添加后的结果返回给result,三者之中,性能最差。
s2方法:编译器对“+”进行优化,合并"A"+"B"+"C"为“ABC”,直接赋给result,三者之中,性能最好。
s3方法:1次创建StringBuilder对象,3次调用append方法添加字符串,1次调用toString方法把添加后的结果返回给result,三者之中,性能居中。
4)总结:
在做字符串的连接操作时,append方法未必是最好的。
等号右侧有变量参与的字符串“+”操作(例如:result += "A"),jvm在做连接时,是创建一个新的StringBuilder对象,然后使用其append方法来实现连接,等号右侧没有变量参与的字符串“+”操作(例如:result = "A" + "B" + "C"),jvm在做连接时,会对右侧的连接操作进行优化,将其合并成一个字符串,然后赋给左边的变量,此时就变成了一次简单的赋值过程。
5)补充
5.1)代码:
public static String s4() { String result = ""; result = result + "A" + "D"; return result; } public static String s5() { String result = ""; result += "A" + "D"; return result; }
5.2)分析:
Javap查看字节码:
由上图可知:
s4方法:1次创建StringBuilder对象,3次调用append方法添加字符串(A和D各占一次),1次调用toString方法把添加后的结果返回给result。
s5方法:1次创建StringBuilder对象,2次调用append方法添加字符串(A和D经优化变成AD,所以A和D加起来仅占一次),1次调用toString方法把添加后的结果返回给result。
5.3)总结:
s4和s5中等号右侧都有变量参于进行字符串的“+”操作(result),所以都会创建StringBuilder对象,并使用其append方法实现连接。
s4中使用的是“=”,所以等号右侧显式的指出了result变量参与字符串的“+”操作,在这种情况下,A和D分两次append完成,而s5中使用的是“+=”,所以等号右侧隐式的指出了result变量参与字符串的“+”操作,在这种情况下,A、D合并成AD,一次append完成。
6)扩展
为什么你会觉得StringBuilder(或StringBuffer)内存占用少呢?
我是这样考虑的:
(1)我们最终想要的是什么?
我们最终想要是一个字符串,用更加准确一点的语言来说,我们最终想要是在堆上开辟一块内存,在该内存中放入我们想要的字符串,然后把该内存的起始地址返回并放入我们的变量中,以使我们持有对该内存的引用。
(2)StringBuilder(或StringBuffer)的作用是什么?
StringBuilder的作用是为了帮住我们完成上面的操作。
(3)为什么要用StringBuilder来完成?
因为String对象是不可变的,如果要想对现有的String对象做修改,我们必须借助StringBuilder这一中间对象,不管我们是自己创建一个StringBuilder还是jvm帮我们创建。
(4)通过StringBuilder我们怎样才能得到我们想要的字符串?
通过调用StringBuilder的toString方法来返回我们的字符串,确切的说应该是返回StringBuilder帮我们维护的堆上一块内存的引用,在该内存中StringBuilder已经把我们想要的字符串放到里面了。
(5)调用完StringBuilder的toString之后,StringBuilder会怎样?
StringBuilder会消亡,因为它的生命周期已经结束。
(6)那我们最终得到的是什么?
我们最终得到的就是我们想要的,即:堆上分配的一块存放我们最终想要字符串的内存,并且这块内存的起始地址已经放到了我们的变量中,我们已经持有了对该内存的引用。
通过上面的分析我们可以看到,StringBuilder只是一个中间态,它的作用只是帮助我们完成我们想要的操作,达到目的,StringBuilder便会消亡,但这个中间态的出现必然会占用内存(例如它的类的加载,它的实例对象的创建),如果我们可以避开这个中间态(上面的s2方法中说的那种情况),那性能自然就会提高,虽然我没试过。
相关文章推荐
- Java解惑之String的"+"一定差于StringBuilder的append吗?
- java中String+String与StringBuilder的append()方法的效率问题
- 从头认识java-11.2 "+"与StringBuilder
- java String 中替换"\"为"\\"
- StringBuilder的append、StringBuffer的append和String str = "a"+"b"的区别?
- 【Java性能】你需要知道的:Java字符串连接使用"+"和StringBuilder性能比较
- "java.lang.ClassNotFoundException: org.apache.commons.lang.StringUtils"的解决办法
- stringBuilder.AppendFormat("{0}-{1}-{2}-{3}!",1,"Hi",2,"Bye");
- java String 中的特殊符号 "." "|" "*" "\" "]"
- Java - "==" and "equals" are different method to String Class
- JAVA String.split()以"\t"分割字符串的问题
- java中,字符串String类型的""和null值的区别
- Programcreek -Java基础之String---用""还是用new String("")
- append进StringBuilder里的字符串是""还是"null"? Java
- Java中的"=="和"equals()"的区别 String中的单例模式
- Java字符串之String与StringBuilder
- Java中String,StringBuffer和StringBuilder的区别
- java字符串(1):String,StringBuffer,StringBuilder的使用与区别
- 2015年11月26日 Java基础系列(一)之String与StringBuffer与StringBuilder的区别
- 探秘Java中String、StringBuilder以及StringBuffer