String
jdk9对String的实现进行了优化,内部不再是char数组,而是byte数组。
当字符都是Ascii字符的时候,将使用一个字节表示一个字符,而不是UTF-16BE编码。
String内部的char数组是final类型的,每次拼接要重新分配内存。
为了高效,在较多的拼接需求的时候,要使用StringBuilder和StringBuffer类来拼接字符串。
两者的实现几乎一样,只是StringBuffer是线程安全的,这里来看下StringBuilder的源码。
StringBuilder源码的核心是扩容算法。
StringBuilder 扩容机制
StringBuilder 继承抽象类AbstractStringBuilder。
其默认构造,调用父类构造函数并传入16。
public StringBuilder() {
super(16);
}
即默认生成一个长度为16的char数组
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
当拼接字符串,调用append时会通过调用ensureCapacityInternal()方法检查char数组长度是否够用,不够则调用expandCapacity()方法来扩容。
expandCapacity()方法是StringBuilder扩容的核心函数。
使用指数+2扩容算法。
void expandCapacity(int minimumCapacity) {
int newCapacity = value.length * 2 + 2;
if (newCapacity - minimumCapacity < 0)
newCapacity = minimumCapacity;
if (newCapacity < 0) {
if (minimumCapacity < 0) // overflow
throw new OutOfMemoryError();
newCapacity = Integer.MAX_VALUE;
}
value = Arrays.copyOf(value, newCapacity);
}
为什么要使用指数扩容算法?为什么要+2?
第一个问题:指数扩容是一种折中的算法,因为一方面要减少内存分配次数,另一方面要避免浪费内存。
不知道最终需要多长的情况下,指数扩容是一种常见的策略,广泛应用于各种内存分配相关的计算机程序中。
第二个问题:为什么要+2?因为StringBuilder提供了一个构造函数,可以指定初始数组的大小public StringBuilder(int capacity)
.
如果capacity = 0的情况下就不能正常扩容了。所以+2。
网友评论