String, StringBuffer和StringBuilder 之间的不同
1. 概述
嗨,大家好
【Java 面试合集】
又来了,今天我们分享的主题是String, StringBuffer和StringBuilder 之间的不同
。 大家别看这个知识点不难,但是里面的细知识很多哦,好了废话不多说了,我们开始吧
2. 区别:
2.1 可变性
String 类型描述
String aa = "10";
aa = "100";
上述代码是不是很眼熟啊,其实就是我们常写的代码,但是你以为它就是一个字符串吗??? 不不不
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
}
其实String底层实现是一个char类型数组,而且被final修饰过了。所以说String是不可变的。
如果是重复赋值的话,从第二次开始后开辟一个新的空间,然后将指针指向修改掉。
StringBuffer/ StringBuilder 类型描述
StringBuffer 继承于 AbstractStringBuilder
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
char[] value;
}
StringBuilder 继承于 AbstractStringBuilder
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
char[] value;
}
通过上述示例可以看到,其实本质上都是char类型数组,只不过没有被final修饰,是可变的。
2.2 StringBuilder 以及StringBuffer 不同
因为StringBuffer被synchronized 所修饰,所以是线程安全的。但是StringBuilder没有被synchronized修饰。
2.3 性能提升
每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象。StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用
public class Test001 {
public static void main(String[] args) {
String str = "";
StringBuilder str1 = new StringBuilder();
long lStart1 = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
str += "a";
}
long lEnd1 = System.currentTimeMillis();
long lStart2 = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
str1.append("a");
}
long lEnd2 = System.currentTimeMillis();
System.out.println("String花费时长:" + (lEnd1 - lStart1)); // 4229
System.out.println("String花费时长:" + (lEnd2 - lStart2)); // 1
}
}
2.4 扩容机制
- 默认的StringBuilder长度, 如果是以无参的方式进行调用的话,默认的长度就是16
public StringBuilder() {
super(16);
}
- 扩容的条件,满足什么条件的时候会选择扩容呢
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
- 扩容的大小. 扩容的公式是:
旧长度 << 1 + 2
. ,例如:旧长度是10的话,新的长度就是22
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2;
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
- 为什么要执行+2呢
因为我们可以在执行new StringBuilder
的时候,传递一个初始化的长度。如果没有+2的操作,传递的初始化长度又是0. 那么初始化的长度就是0.
目的为了防止初始容量是0.