文章目录
- 倡议
- “+”语法糖操作的本质
- String、StringBuilder、StringBuffer性能比较
- 一个特殊的例子
- 总结
倡议
在《阿里java开发手册》中,对于Java字符串的拼接有一条规则如下:
- 22.【推荐】循环体内,字符串的连接方式,使用 StringBuilder 的 append 方法进行扩展。
“+”语法糖操作的本质
语法糖:语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得兰丁发明的一个术语,指计算机语言中添加的某种语法,这种语服务器托管网法对语言的功能没有影响,但是更方便程序员使用。语法糖让程序更加简洁,有更高的可读性。
“+”号操作符必须是字符串拼接最常用的一种了,没有之一。使用“+”拼接字符串,其实只是Java提供的一个语法糖。那么,我们就来解一解这个语法糖,看看他的内部原理到底是如何实现的。
还是这样一段代码。我们把他生成的字节码进行反编译,看看结果。
String str1= "唐伯虎";
String str2= "点香烟";
String endStr = str1+ "," + str2;
Dos反编译后的内容如下(反编译class文件的命令:javap -c 类名)。
String str1= "u5510u4f2fu864e"; //唐伯虎
String str2= "u70b9u9999u70df"; //点香烟
String endStr = (new StringBuilder()).append(str1).append("服务器托管网,").append(str2).toString();
通过查看反编译以后的代码,我们可以发现,原来字符串常量在拼接过程中,是将String转成了StringBuilder后,使用其append方法进行处理的。
那么也就是说,Java中的“+”对字符串的拼接,其实现原理是使用StringBuilder.append()方法。
String、StringBuilder、StringBuffer性能比较
三者在执行速度方面的比较:StringBuilder > StringBuffer > String 。原因:
- String:字符串常量
- StringBuffer:字符串变量(有同步锁)
- StringBuilder:字符串变量(无同步锁)
具体分析下String:从上面的名字可以看到,String是”字符串常量”,也就是不可改变的对象。源码如下:
public final class String{}
对于上面这句话的理解你可能会产生这样一个疑问 ,比如这段代码:
String str = "唐伯虎";
str = str + "点香烟";
System.out.print(str); // result : "唐伯虎点香烟"
我们明明改变了String型的变量str啊,为什么说是没有改变呢?我们来看一下这张对String操作时内存变化的图:
我们可以看到,初始String值为”唐伯虎”,然后在这个字符串后面加上新的字符串”点香烟”,这个过程是需要重新在栈堆内存中开辟内存空间的,最终得到了”唐伯虎点香烟”字符串也相应的需要开辟内存空间,这样短短的两个字符串,却需要开辟三次内存空间,不得不说这是对内存空间的极大浪费。
而,对于StringBuilder、StringBuffer,他们俩均属于字符串变量,是可改变的对象,每当我们用它们对字符串做操作时,实际上是在一个对象上操作的,这样就不会像String一样创建一些而外的对象进行操作了,速度自然就相对快了。
至于StringBuilder非线程安全、StringBuffer线程安全,这一点大家应该都清楚,StringBuffer的很多方法都被关键字synchronized 修饰了,而StringBuilder没有。
一个特殊的例子
String str = "This is only a" + " simple" + " test";
StringBuffer builder = new StringBuilder("This is only a").append(" simple").append(" test");
这段代码,经测试发现,生成str对象的速度远高于builder,而这个时候StringBuilder居然速度上根本一点都不占优势。为什么呢?
其实这是JVM的一个把戏,实际上:
String str = “This is” + ” a ” + “demo”; 等同于 String str = “This is a demo”;
这是因为,在JVM优化时,如果是多个固定字符串拼接,会将这些固定字符串进行预处理,当成一个整体的字符串,相当于仅声明一个常量,所以并不需要太多的时间。
但大家这里要注意的是,如果字符串拼接的多个元素中有其他String对象的话,速度就没那么快了,譬如:
String str = "唐伯虎";
str = str + "点香烟";
或者:
String str5 = "啦啦啦";
String str6 = str5 + "嘻嘻嘻";
这时候JVM会规规矩矩的按照原来的方式去做。
总结
- 如果不是在循环体中进行字符串拼接的话,直接使用 String 的 “+” 就好了。
- 单线程循环中操作大量字符串数据 → StringBuilder.append()
- 多线程循环中操作大量字符串数据 → StringBuffer.append()
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net