我们来聊聊String、StringBuffer与StringBuilder
String:字符串常量
StringBuffer:字符创变量
StringBuilder:字符创变量
首先常量,也就是不可改变的对象
那String怎么拼接字符串的呢,你肯定以前听过你自己的老大说String效率低,频繁创建对象!
我们先开始聊聊String
看一个例子:
String str = "love";
String str1="you"
str = str+str1;
System.out.print(str);
你觉得jvm会怎么对待这段代码,常量是不可改变的,运行过程
- 虚拟机划分一块内存同时引用赋予对象(str),赋值(“love”)
- 虚拟机划分新的一块内存同时引用赋予对象(str),赋值(“love”+“you”)
- 销毁旧的对象和内存
String的低效在于他的本质常量
同时String也不能用在多线程中,同时java也需要解决他的低效(常量问题)
先解决低效StringBuilder出现了
聊聊StringBuilder
StringBuilder和StringBuffer都是集成AbstractStringBuilder
AbstractStringBuilder中采用一个char数组来保存需要append的字符串
char数组有一个初始大小,当append的字符串长度超过当前char数组容量时,则对char数组进行动态扩展,也即重新申请一段更大的内存空间,然后将当前char数组拷贝到新的位置,因为重新分配内存并拷贝的开销比较大,所以每次重新申请内存空间都是采用申请大于当前需要的内存空间的方式,这里是2倍。
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);
}
append(拼接字符串)
/**
* value 用来存储字符串.
*/
char value[];
/**
* 有效字符串的数目.
*/
int count;
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);
}
//getChars将字符串复制到指定的位置
str.getChars(0, len, value, count);
count = newCount;
return this;
}
Stringbuild和Stringbuffer都是调用父类方法
但是StringBuild并不是线程安全的,虽然他是效率最高的,为了解决线程安全问题,能够在多线程中使用Stringbuffer出现了
聊聊StringBuffer
其实Stringbuild和Stringbuffer这两货区别不大,效率问题呢,Stringbuffer差点的原因在于。。。我们先看几段代码
public synchronized StringBuffer append(CharSequence s) {
toStringCache = null;
super.append(s);
return this;
}
public synchronized StringBuffer delete(int start, int end) {
toStringCache = null;
super.delete(start, end);
return this;
}
synchronized关键字,给方法加锁,同时也给jvm增加了性能上的消耗,减少了运行的速度
之所以慢就在于synchronized
总结:
三者在执行速度方面的比较:StringBuilder > StringBuffer > String
多线程下使用StringBuffer
一般情况下如果就两个字符串拼接String 也是可以的,区别不大
多个拼接还是StringBuilder