字符串相关类
String类
String是一个典型的数组应用
结合源码来看:
private final char value[];
private int hash; // Default to 0
在String类中声明了一个私有的常量数组,因此声明后的值外部无法直接操作,但是:
public String() {
this.value = new char[0];
}
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
通过String提供的构造方法可以操作该值,并且只能被定义一次
这段代码表示在String类中对象创建后无法修改,重新赋值表示重新创建了一个新的对象;
equals和==
equals比较内容是否相等,==比较引用地址是否相等;
但是有一点需要注意,对象只有初始化才会在堆中创建该对象的属性;如果:
String a = "aaa";
String b = "aaa";
System.out.print(a==b);
最后结果为true,这是因为,a和b并未创建新的对象,而是直接将指针指向了常量池里已经加载过的“aaa”这个值
new关键字
String a = new String("abc");
String b = "abcd";
这两种写法是有明显区别的;
a的value会被加载到堆中,value的指针指向常量池中的“abc”;
b是指针直接指向常量池中的"abcd";
因此可以说new一个String对象实际该对象创建了两次;
StringBuilder类
新建一个StringBuilder对象,跳转进去查看它的源码可以发现,它的默认长度为16
public StringBuilder() {
super(16);
}
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
传入int类型代表长度:
public StringBuilder(int capacity) {
super(capacity);
}
传入String类型代表:
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
返回一个字符串长度+16的char类型数组并追加String字符串
StringBuilder自动扩容
在使用StringBuilder中的append方法追加字符串时,如果我们在初始化时未指定长度,那它的默认长度为16,如果我们追加的字符超过该长度,StringBuilder会调用一个自动扩容的方法,如下:
/**
* This implements the expansion semantics of ensureCapacity with no
* size check or synchronization.
*/
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);
}
这一段是StringBuilder源码当中对于使用append方法扩容的方法,当追加的字符长度超过当前定义StringBuilder的长度时,新建一个原数组长度2倍+2的一个新数组(如果新建的还是不够,继续新建,就数组无指针引用,将会被回收),最后替换数组,返回新数组
StringBuffer
和StringBuilder基本一致;
StringBuilder线程不安全,效率高
StringBuffer线程安全,效率低
因为StringBuffer中所有的方法都添加了synchronized关键字来表示同步,因此StringBuffer是线程安全的,但是因为是多线程,要一个方法关闭后,另一个方法才能被调用,因此,它的效率比较低;
一般声明在方法块中的局部变量大多都不会考虑线程安全,因此,从效率触发,我们选择较多的还是StringBuilder
String和StringBuilder的区别
我们首先来分析String和StringBuilder源码中是怎样定义它们的值
String:(摘取片段)
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
StringBuilder:(摘取片段)
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
char[] value;
/**
* The count is the number of characters used.
*/
int count;
从它们的定义我们可以看出String定义的值是private final char value[],一个私有的常量数组,因此它的值是不可更改的;
而StringBuilder (继承至AbstractStringBuilder )声明的是一个default char[] value ;同一个包下的其他类可对它进行操作;
因此我们可以得出:
String是不可变字符序列,而StringBuilder是可变字符序列;又因为String对象不可变,变则相当于重新创建对象,因此从运行效率来说,StringBuilder是远远大于String的,因此它们的关系可表示为StringBuilder>StringBuffer>String