String和StringBuffer有何区别?或许我们所熟知的是String是定长而StringBuffer是变长的,这种说法当然是没错的,而事实上,在一般的情况下,String和StringBuffer两者用起来是没有任何区别的。
那么所说的一般情况是指那些情况呢?比如我们定义一个字符变量:
String str = “”;
StringBuffer str = new StringBuffer(“”);
我们只是对这变量进行一些常规的字符操作,比如用来得到form表单提交的字符串等等,在这种情况下,去区分String和StringBuffer的区别是没有任何意义的。那么在什么非一般的情况下来做这种区分有意义呢?
假如有这样一个需求,有至少50万个词,需要你将一个词一个词连接起来(每个词后加回车符),然后写入到文件中,那么此时,你该选择String还是StringBuffer呢?如果这时你还认为像上面所说的那样随便选择一个就行了的话,那么结果很可能就会变得恐怖起来,因为你的程序很可能在运行到一半的时候会挂掉!而你还以为是程序哪里错了,是不是出现了死循环?实际上,你的程序逻辑并没错,你只是错在用了String而不是StringBuffer上。
String的构造函数是这样写的:public String() {
this.offset = 0;
this.count = 0;
this.value = new char[0];
}
构造出了一个空的字符数组,而StringBuffer却是构造出了一个16个元素的字符数组,如下:public StringBuffer() {
super(16);
}
而这还并不能说明情况,再看看StringBuffer的append方法:public AbstractStringBuilder append(String str) {
if (str == null) str = "null";
int len = str.length();
if (len == 0) return this;
int newCount = count + len;
if (newCount > value.length)
expandCapacity(newCount);
str.getChars(0, len, value, count);
count = newCount;
return this;
}
如果当前新的个数(已有的数组长度加上新增加的Str长度)大于了目前数组已有的长度,那么就会调用expandCapacity(newCount);进行扩容,expandCapacity的方法如下:void expandCapacity(int minimumCapacity) {
int newCapacity = (value.length + 1) * 2;
if (newCapacity < 0) {
newCapacity = Integer.MAX_VALUE;
} else if (minimumCapacity > newCapacity) {
newCapacity = minimumCapacity;
}
value = Arrays.copyOf(value, newCapacity);
}
扩充规则是:
在已有数组长度上加1,然后乘以2得到一个新的容量值newCapacity,如果新的容量值小于0,那么将Integer.MAX_VALUE赋给newCapacity,如果是minimumCapacity > newCapacity,则将newCapacity = minimumCapacity;最后再生成一个扩容后的新的数组。
StringBuffer的这个扩容机制就是与String截然不同的地方,也是StringBuffer在处理大容量数据时优于String的地方,也就是利用数组的扩容,理论上,StringBuffer的最大容量可以达到Integer.MAX_VALUE的长度,而String,我查看了其源码,没有发现这样的扩容机制。
再回到上面说的那个问题,这个也不是我随意想出来的一个问题,事实上是我在实际工作中遇到的一个问题,当时我用String的时候,发现程序运行不下去,在确认程序绝对没错之后,我猛然想起了平常一说就会挂在嘴边的String和StringBuffer的区别,才突然意识到这里可能正是这两者的区别所在,于是将String改为了StringBuffer,之后程序运行顺利,庞大的数据也能顺利连接起来。
所以做个总结就是:当你需要用字符串来处理大量数据的时候,一定要记得用StringBuffer而不是String,反之,两者均可用。
在Java中,有好多的对象彼此间像String和StringBuffer一样很相似,在很多情况下两者所应用的效果也是非常类似没差别,只有在一些特殊的情况下,比如大量数据处理、高并发线程等等情况下,两者间的区别才非常明显地显现出来,这就是我们要在程序编写中尽量要意识到的问题。