StringBuffer类源码剖析
一、StringBuffer类的简介
StringBuffer
是线程安全
、可变
的字符序列。StringBuffer类似于String,但可以被修改。在任何时间点,它都包含一些特定的字符序列,但序列的长度和内容可以通过某些方法调用来更改。StringBuffer可由多个线程安全使用,必要时同步(synchronized
)这些方法,以便任何StringBuffer实例
上的所有操作都表现得好像它们以某种串行顺序
发生,这与所涉及的每个线程进行的方法调用的顺序一致。
注意:每当发生涉及源序列的操作(例如从源序列append或insert)时,此类仅在执行操作的字符串缓冲区上同步,而不在源上同步。请注意,虽然StringBuffer设计为可以安全地从多个线程并发使用,但如果构造函数或追加或插入操作传递了跨线程共享的源序列,则调用代码必须确保操作在操作期间具有一致且不变的源序列视图。这可以通过在操作调用期间保持锁
、使用不可变的源序列
或不跨线程共享源序列
来满足。
二、StringBuffer类的构造方法
StringBuffer类的构造方法与StringBuilder类的构造方法如出一辙,就不过多解释了。
1 2 3
| public StringBuffer() { super(16); }
|
1 2 3
| public StringBuffer(int capacity) { super(capacity); }
|
1 2 3 4
| public StringBuffer(String str) { super(str.length() + 16); append(str); }
|
1 2 3 4
| public StringBuffer(CharSequence seq) { this(seq.length() + 16); append(seq); }
|
三、StringBuffer类的方法
与构造函数类似,StringBuffer的所有方法基本都是通过调用父类的相应方法实现的,多出的仅仅是 synchrinized
修饰符,重点功能实现在于父类AbstractStringBuilder
,参考之前的AbstractStringBuilder类源码剖析。不过需要注意一点,StringBuffer类引入了一个新字段toStringCache
,顾名思义该字段就是toString
方法的缓存,一旦StringBuffer被修改了,该字段也就失效了。
1 2 3 4 5
|
private transient String toStringCache;
|
四、StringBuffer类的toString方法
toString
方法会检查上一次调用toString
的缓存字段是否失效,如果已经失效则重新创建一个字符串(深拷贝
),并且toStringCache
字段指向该字符串;否则直接返回toStringCache
的一个副本(浅拷贝
),不过注意的是String是不可变类,共享String的底层字节数组不存在线程安全问题!。
1 2 3 4 5 6 7 8
| public synchronized String toString() { if (toStringCache == null) { return toStringCache = isLatin1() ? StringLatin1.newString(value, 0, count) : StringUTF16.newString(value, 0, count); } return new String(toStringCache); }
|
之所以说深拷贝
还是浅拷贝
是有依据的,前者会拷贝底层的字节数组,后者只是引用的指向!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public static String newString(byte[] val, int index, int len) { return new String(Arrays.copyOfRange(val, index, index + len), LATIN1); }
public static byte[] copyOfRange(byte[] original, int from, int to) { int newLength = to - from; if (newLength < 0) throw new IllegalArgumentException(from + " > " + to); byte[] copy = new byte[newLength]; System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); return copy; } public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
public String(String original) { this.value = original.value; this.coder = original.coder; this.hash = original.hash; }
|
五、StringBuffer类的序列化/反序列化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| private synchronized void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { java.io.ObjectOutputStream.PutField fields = s.putFields(); char[] val = new char[capacity()]; if (isLatin1()) { StringLatin1.getChars(value, 0, count, val, 0); } else { StringUTF16.getChars(value, 0, count, val, 0); } fields.put("value", val); fields.put("count", count); fields.put("shared", false); s.writeFields(); }
private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { java.io.ObjectInputStream.GetField fields = s.readFields(); char[] val = (char[])fields.get("value", null); initBytes(val, 0, val.length); count = fields.get("count", 0); }
|