今天回顾巩固了一下java的基础知识,那么String、StringBuilder、StringBuffer之间有什么区别呢?
尝试查看源码之后,有了一个清晰的认识。
首先大体说明,通常情况下大家都知道,String是不可变的字符串对象,StringBuilder、StringBuffer是可变的,其中StringBuilder线程不安全,StringBuffer线程安全,具体情况如下:
String:
源码注释写到:“Strings are constant; their values cannot be changed after they are created.“
具体到代码中:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
private final char value[];<pre name="code" class="java"> <span style="font-family: Arial, Helvetica, sans-serif;">…</span><span style="font-family: Arial, Helvetica, sans-serif;">…</span><pre name="code" class="java">}
看一看到,String其实就是一个char数组,但是由于使用了private修饰,且没有给出外部接口,又使用了final修饰,使得这个String对象一旦创建,就不能进行修改。
至于为什么可以对String进行赋值等操作,是因为对String进行赋值等操作以后,其实是给了String变量一个新的String对象,而之前被创建的对象依然存在于内存中。
StringBuilder和StringBuffer:
public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence
public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence
从源码中可以看出StringBuilder和StringBuffer都继承于AbstractStringBuilder,实现的接口也是一致的。
再来看AbstractStringBuilder:
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;
接口AbstractStringBuilder中,可以看到,StringBuilder和StringBuffer其实也是char数组,只不过没有用private和final进行修饰,这意味着他们是可变的。
其中最重要的一个方法就是append,同个这个方法,使得他们可以对数组进行扩容,我们都知道数组一旦被定义,那么长度就是一定的,不能再进行改变了,那他们是怎么做到对数组进行扩容的呢,于是查看了AbstractStringBuilder中以下源码:
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);
}
public static char[] copyOf(char[] original, int newLength) {
char[] copy = new char[newLength];
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
这里可以发现,其实并不是对原本的数组进行了修改,而是新建了一个数组,将原数组内容进行了copyOf操作,让value引用了新数组,旧的数组等待被回收。
而后通过观察发现,他们实现的方法也基本一致。
StringBuilder:
private StringBuilder append(StringBuilder sb) {
if (sb == null)
return append("null");
int len = sb.length();
int newcount = count + len;
if (newcount > value.length)
expandCapacity(newcount);
sb.getChars(0, len, value, count);
count = newcount;
return this;
}
public StringBuilder append(StringBuffer sb) {
super.append(sb);
return this;
}
StringBuffer:
public synchronized StringBuffer append(StringBuffer sb) {
super.append(sb);
return this;
}
这里可以看出唯一的区别是StringBuffer的方法基本上都有synchronized修饰,synchronized本意是同步的,java中用它来修饰一个方法或一块代码时,能保证同一时刻最多只有一个线程能执行改代码。所以有synchronized修饰即线程安全的。
比较的同时,通读了3个类中的源代码,发现了很多方法是以前不曾注意过的,但是都很有用。