String,StringBuilder,StringBuffer区别
1.练习
public static void main(String[] args) {
String str1 = "xxxx"; //1
String str2 = "xxxx";
String str3 = new String("xxxx"); //3
String str4 = "" + str1; //4
String str5 = new String("xxxx").intern(); //5
System.out.println(str1 == str2);
System.out.println(str1 == str3);
System.out.println(str1 == str4);
System.out.println(str1 == str5);
}
运行结果:
true
false
false
true
2.说明
-
String类中真正存储字符串的是一个char[]数组,并且是final修饰的,这也就是String类不可变的根源;
-
字符串的字面量会保存在常量池中,不管以第一行还是第三行实例化字符串对象,在常量池中只有一个"xxxx"
-
通过new String(“xxxx”)方式实例化对象时,会在虚拟机堆上创建对象,也就是说str3指向的是堆上对象的引用,str3中的char[]指向的是常量池中的“xxxx”,而str1对象中的char[]直接指向的是常量池中的"xxxx"
-
第四行原理与第三行类似,在堆上创建对象
-
intern()方法会将字符串添加到常量池中,前提是当前常量池中不存在
3.原理分析
3.1 StringBuffer与StringBuilder
特点是字符串可变,均继承自抽象类AbstractStringBuilder,字符串保存在AbstractStringBuilder类的char[]数组中,注意没有final修饰,区别在于StringBuffer线程安全,StringBuilder线程不安全。StringBuffer之所以线程安全是因为对字符串操作的方法加了synchronized关键字修饰,因此效率会低一点,对于不存在多线程操作的字符串来说,推荐使用StringBuilder。具体源码实现方面二者基本一致,下面以StringBuilder分析,StringBuffer类似,其实主要是char[]的动态扩容机制,这种机制在集合,map中也有用到
3.2 StringBuffer源码分析
从StringBuffer的无参构造器开始
public StringBuilder() {
super(16); //无参构造器数组长度16
}
再看两个有参构造器。
public StringBuilder(int capacity) {
super(capacity);
}
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
在实例化StringBuffer时会调用父类的构造方法,它的父类AbstractStringBuilder
AbstractStringBuilder(int capacity) {
value = new char[capacity]; //底层实例化一个char[]数组value,
}
以append()方法为例,说明数组扩容。
public StringBuilder append(String str) {
super.append(str); //调用父类方法
return this;
}
AbstractStringBuilder类中的append方法:
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
//count表示当前数组中字符的个数,也就是字符串的长度。
ensureCapacityInternal(count + len); //执行扩容
str.getChars(0, len, value, count); //将str内容添加到数组中
count += len;
return this;
}
private void ensureCapacityInternal(int minimumCapacity) {
// 追加后的长度大于value.length的话,扩容
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity)); //这里会创建一个新的数组,新数组中的内容还和原数组一样
}
}
private int newCapacity(int minCapacity) {
//扩大为原来的2倍加2
int newCapacity = (value.length << 1) + 2;
if (newCapacity - minCapacity < 0) { //扩大后2倍加2后还是不够
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0) //溢出或者超出最大值,溢出报错
? hugeCapacity(minCapacity)
: newCapacity;
}
private int hugeCapacity(int minCapacity) {
if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
return (minCapacity > MAX_ARRAY_SIZE)
? minCapacity : MAX_ARRAY_SIZE;
}