本文通过StringBuffer 源码,来理解append(),方法。
============================================================================
str.append(""); 是用来拼接字符窜,一般人我不告诉他。
一、直接上示例:
public class TestString {
public static void main(String[] args) {
StringBuffer buffer = new StringBuffer();
buffer.append("hello ");
buffer.append("world!");
System.out.println(buffer); //结果 hello world!
}
}
二、断点跟踪:(以下都是jdk1.8源码)
1、进入StringBuffer类的 append(String str) 方法: str = hello, 传进来。
public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence
{
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
}
2、调用了父类的方法super.append():str=hello ,传到父类的方法。
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len); //count :存放的字符的长度 现在是0, len = 5
str.getChars(0, len, value, count);
count += len;
return this;
}
2.1、 进入 ensureCapacityInternal(), 判断字符总长度有没有超过 字符数组的容量值。
private void ensureCapacityInternal(int minimumCapacity) { // 0+5
// overflow-conscious code
if (minimumCapacity - value.length > 0) { //value.length 默认初始值为16
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
注意区分下面两者:
value.length : 是 char[] value 数组的 长度,默认初始值 16.
str.length() :字符串的长度,(也可以理解为字符的个数)。
/**
* Returns the length (character count).
*
* @return the length of the sequence of characters currently
* represented by this object
*/
@Override
public int length() {
return count; //看看,返回的count
}
2.2、 当minimumcapacity > value.length, 字符数组开始扩容。
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2; //容量扩大为 原来的2倍+2
if (newCapacity - minCapacity < 0) { //如果还是比字符总长度小, 那么 总长度就设置为容量。
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
3、进入String类的方法 getChars(srcBegin,srcEnd, char [] dest, int destBegin );
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
if (srcBegin < 0) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd > value.length) {
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin > srcEnd) {
throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
}
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}
难点:
难点a、这里可能会比较不太明白, 在进入抽象父类的方法后, 又调用了String类的getChar() 方法。
注意: str.getChar(); 这里的str 是是传入 “hello”字符窜。 所以,其实这里已经创建了一个String类,String str ="hello";
并且, String类,在内部定义了一个 字符数组,private final char[] value ; 字符串会被分解存放在这个数组里面。所以
“hello”, 被存储为 char [] value = {"h","e","l","l","o"}。如果理解这里的话, 进入< 3 > 方法的几个参数就好理解了。
难点b、System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd-srcBegin);
最后这个方法的参数值 : value, 到底代表的是那个类的 char[] 数组呢?
因为 <3 >方法是在String类中调用的, 所以value 所指的是 String 类中维护的 那个 char [] value = {"h","e","l","l","o"};
参数解释:
srcBegin: 复制源数组的开始位置(数组下标), 例如: 这里srcBegin= 0 , 所以从 字符 h 开始复制。
srcEnd : 源数组的结束位置, 这里 srcEnd = len, "hello"的长度。
char dst[] : StringBuffer 存储的字符数组。(StringBuffer 类一 维护了一个 字符数组 char value []), 因为命名都一样,可能会有点搞混。
srcEnd -srcBegin: 要被复制的元素的个数。其实完全可以用 srcEnd 来表示就可以了。
4、最后进入System类的 方法 arraycopy();数组复制。
三、结论:
由此可以看出, StringBuffer拼接字符窜的 实质是:char类型数组的扩容复制。
============================================================================本文到此结束,后续内容继续补充。