在Java中,我们操作最多的类应该就是String了,String类提供了很多字符串操作的方法,其实功能上所有操作都能用String解决,那么我们为什么还要有StringBuffer和StringBuilder呢?是性能好吗?好多少呢?以及为什么好呢?
首先我们来看String的生成“abc”的三个代码,我们知道Stirng的==判断的是地址,大家猜下结果。
String a = new String("abc"); String b = "abc"; String c = "ab"+"c"; System.out.println(a == b); System.out.println(a == c); System.out.println(b == c);结果是false、false、true.这是因为“ab”+“c”会先编译成"abc",而且相信你听过在内存中有块专门存储String的区域,当相同时会直接把引用给c。但是a就不一样了,new的时候会先开辟一个对象的堆内存。而且编辑工具很可能会提醒你new是没意义的。那你可能会说我就想要一个特殊的堆地址不行吗,然后我的String就在这个堆里了。其实不行的,会换堆。我们来看看String类。
/** The value is used for character storage. */ private final char value[];可以看出String存在一个char数组中,而数组我们都知道是定长的。当长度改变时我们得到的一定是另一个数组了,而且由于是final,也就是说一个String对象只能有一个char数组。要变长就得另一个String对象,也就是另一个堆了。那么我们不能不用final吗。当然可以,所以当长度改变的时候就有了StringBuffer和StringBuilder了。他们继承的都是AbstractStringBuilder,在JDK1.5加入的。
/** * The value is used for character storage.可以看到不是final了,而且新的数组生成用的是Arrays,copyOf方法。那么StringBuffer和StringBuilder的区别是什么呢。很多人可能已经知道了是线程安全不安全。如下StringBuilder是*/
char[] value;.....
value = Arrays.copyOf(value, newCapacity);....
public StringBuilder delete(int start, int end) { delete0(start, end); return this; }StringBuffer是下面,主要是很多方法和重写父类方法时都加了同步锁。
@Override public synchronized void trimToSize() { super.trimToSize(); }那么最后性能呢,我们来写个小程序测试下.public synchronized StringBuffer delete(int start, int end) { delete0(start, end); return this; }
public static void main(String[] args) { long time = System.currentTimeMillis(); StringBuilder a = new StringBuilder(""); for (int i = 0; i < 100000; i++) { a.append("1"); } System.out.println(time-System.currentTimeMillis()); time = System.currentTimeMillis(); StringBuffer b = new StringBuffer(""); for (int i = 0; i < 100000; i++) { b.append("1"); } System.out.println(time-System.currentTimeMillis()); time = System.currentTimeMillis(); String c = ""; for (int i = 0; i < 100000; i++) { c = c +"1"; } System.out.println(time-System.currentTimeMillis()); }输出结果是
-4
-2
-1642
这里-1642容易理解,创建对象和对象重复判断的花销很大。问题是StringBuffer怎么比StringBuilder还快了,这是因为StringBuilder在前面,main程序刚启动肯定慢,当数值再大些就看出差异了,如果再用多线程差异更大些。
结论是当我们要的字符串常改变长度时用StringBuffer和StringBuilder,而当没有同步问题时我们用StringBuilder。