StringBuilder
类提供了众多拼接、插入字符的方法,因此在一定情况下,使用很广泛,以下是对StringBuidler的部分解析,有兴趣的朋友可以查看源代码
/android-26/java/lang/StringBuilder.
StringBuilder
类也封装了一个字符数组,定义如下:
char[] value;
与String
不同,它不是final
的,可以修改。另外,与String
不同,字符数组中不一定所有位置都已经被使用,它有一个实例变量,表示数组中已经使用的字符个数,定义如下:
int count;
StringBuilder
继承自AbstractStringBuilder
,它的默认构造方法是:
public StringBuilder() {
super(16);
}
调用父类的构造方法,父类对应的构造方法是:
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
也就是说,new StringBuilder()
这句代码,内部会创建一个长度为16的字符数组,count的默认值为0。
append的实现
目前StringBuilder的append支持以下方法
- boolean
- char
- char[]
- char[], int, int
- CharSequence
- CharSequence, int, int
- double
- float
- int
- long
- Object
- String
- StringBuffer
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
public AbstractStringBuilder append(String str) {
if (str == null) str = "null";
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
}
append
会直接拷贝字符到内部的字符数组中,如果字符数组长度不够,会进行扩展,实际使用的长度用count
体现。具体来说,ensureCapacityInternal(count+len)
会确保数组的长度足以容纳新添加的字符,str.getChars
会拷贝新添加的字符到字符数组中,count+=len
会增加实际使用的长度。
ensureCapacityInternal
的代码如下:
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
newCapacity
的代码如下:
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2;
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
如果MAX_ARRAY_SIZE - newCapacity < 0
,则调用hugeCapacity
方法进行增大容量,否则返回newCapacity的大小,hugeCapacity
的代码是:
private int hugeCapacity(int minCapacity) {
if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
return (minCapacity > MAX_ARRAY_SIZE)
? minCapacity : MAX_ARRAY_SIZE;
}
扩展的逻辑是,分配一个足够长度的新数组,然后将原内容拷贝到这个新数组中,最后让内部的字符数组指向这个新数组,这个逻辑主要靠下面这句代码实现:
value = Arrays.copyOf(value, newCapacity(minimumCapacity));
String类中的getChars方法
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
if (dst == null) {
throw new NullPointerException("dst == null");
}
if (srcBegin < 0) {
throw new StringIndexOutOfBoundsException(this, srcBegin);
}
if (srcEnd > length()) {
throw new StringIndexOutOfBoundsException(this, srcEnd);
}
int n = srcEnd - srcBegin;
if (srcEnd < srcBegin) {
throw new StringIndexOutOfBoundsException(this, srcBegin, n);
}
if (dstBegin < 0) {
throw new ArrayIndexOutOfBoundsException("dstBegin < 0. dstBegin=" + dstBegin);
}
// dstBegin can be equal to dst.length, but only in the case where zero chars are to be
// copied.
if (dstBegin > dst.length) {
throw new ArrayIndexOutOfBoundsException(
"dstBegin > dst.length. dstBegin=" + dstBegin + ", dst.length=" + dst.length);
}
if (n > dst.length - dstBegin) {
throw new ArrayIndexOutOfBoundsException(
"n > dst.length - dstBegin. n=" + n + ", dst.length=" + dst.length
+ "dstBegin=" + dstBegin);
}
getCharsNoCheck(srcBegin, srcEnd, dst, dstBegin);
}
insert实现
目前StringBuilder的insert支持以下方法
- int, boolean
- int, char
- int, char[]
- int, CharSequence
- int, CharSequence, int, int
- int, double
- int, float
- int, int
- int, long
- int, Object
- int, String
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
@Override
public StringBuilder insert(int offset, String str) {
super.insert(offset, str);
return this;
}
父类中的实现
public AbstractStringBuilder insert(int offset, String str){
if ((offset < 0) || (offset > length()))
throw new StringIndexOutOfBoundsException(offset);
if (str == null)
str = "null";
int len = str.length();
ensureCapacityInternal(count + len);
System.arraycopy(value, offset, value, offset + len, count - offset);
str.getChars(value, offset);
count += len;
return this;
}
toString实现
字符串构建完后,我们来看toString代码:
@Override
public String toString() {
if (count == 0) {
return "";
}
return StringFactory.newStringFromChars(0, count, value);
}
StringFactory
目的是将长度从0到count的char[]转换成String
public static String newStringFromChars(char[] data) {
return newStringFromChars(data, 0, data.length);
}
public static String newStringFromChars(char[] data, int offset, int charCount) {
if ((offset | charCount) < 0 || charCount > data.length - offset) {
throw new StringIndexOutOfBoundsException(data.length, offset, charCount);
}
return newStringFromChars(offset, charCount, data);
}
// The char array passed as {@code java_data} must not be a null reference.
@FastNative
static native String newStringFromChars(int offset, int charCount, char[] data);
TestStringBuilder
package com.example.test;
import java.util.ArrayList;
public class TestStringBuilder {
public static void main(String[] args) {
testAppend();
testInsert();
}
/**
* 测试Append
*/
private static void testAppend() {
StringBuilder appbuilder = new StringBuilder();
// 追加字符数组
appbuilder.append(new char[] { 'q', 'w', 'e', 'r', 't' });
// 追加字符数组。0表示字符数组起始位置,4表示长度
appbuilder.append(new char[] { 'A', 'S', 'D', 'F', 'G' }, 0, 4);
// 追加float
appbuilder.append(0.123f);
// 追加double
appbuilder.append(1.23456d);
// 追加boolean
appbuilder.append(false);
// 追加char
appbuilder.append('\n');
// 追加int
appbuilder.append(50);
// 追加long
appbuilder.append(11111L);
// 追加StringBuilder对象
appbuilder.append(new StringBuilder("TestStringBuilder"));
// 追加StringBuilder对象。3表示被追加对象的起始位置(包括),12是结束位置(不包括)
appbuilder.append(new StringBuilder("TestStringBuilder"), 3, 12);
// 追加StringBuffer对象。
appbuilder.append(new StringBuffer("TestStringBuffer"));
// 追加StringBuffer对象。4表示被追加对象的起始位置(包括),14是结束位置(不包括)
appbuilder.append(new StringBuffer("TestStringBuffer"), 4, 14);
// 追加String对象。
appbuilder.append("HelloWorld");
// 追加String对象。1表示被追加对象的起始位置(包括),8是结束位置(不包括)
appbuilder.append("WelcomeWorld", 1, 8);
appbuilder.append('\n');
// 在位置0处插入Object对象。此处以ArrayList为例
ArrayList arrayList = new ArrayList();
arrayList.add("1");
arrayList.add("2");
arrayList.add("3");
appbuilder.append(arrayList);
appbuilder.append('\n');
System.out.printf("%s\n\n", appbuilder);
}
/**
* 测试Insert
*/
private static void testInsert() {
StringBuilder insertBuilder = new StringBuilder();
// 在位置0处插入字符数组
insertBuilder.insert(0, new char[] { 'q', 'w', 'e', 'r', 't' });
// 在位置0处插入字符数组。0表示字符数组起始位置,4表示长度
insertBuilder.insert(0, new char[] { 'A', 'S', 'D', 'F', 'G' }, 0, 4);
// 在位置0处插入float
insertBuilder.insert(0, 0.123f);
// 在位置0处插入double
insertBuilder.insert(0, 1.23456d);
// 在位置0处插入boolean
insertBuilder.insert(0, false);
// 在位置0处插入char
insertBuilder.insert(0, '\n');
// 在位置0处插入int
insertBuilder.insert(0, 50);
// 在位置0处插入long
insertBuilder.insert(0, 11111L);
// 在位置0处插入StringBuilder对象
insertBuilder.insert(0, new StringBuilder("TestStringBuilder"));
// 在位置0处插入StringBuilder对象。3表示被在位置0处插入对象的起始位置(包括),12是结束位置(不包括)
insertBuilder.insert(0, new StringBuilder("TestStringBuilder"), 3, 12);
// 在位置0处插入StringBuffer对象。
insertBuilder.insert(0, new StringBuffer("TestStringBuffer"));
// 在位置0处插入StringBuffer对象。4表示被在位置0处插入对象的起始位置(包括),14是结束位置(不包括)
insertBuilder.insert(0, new StringBuffer("TestStringBuffer"), 4, 14);
// 在位置0处插入String对象。
insertBuilder.insert(0, "HelloWorld");
// 在位置0处插入String对象。1表示被在位置0处插入对象的起始位置(包括),8是结束位置(不包括)
insertBuilder.insert(0, "WelcomeWorld", 1, 8);
insertBuilder.insert(0, '\n');
// 在位置0处插入Object对象。此处以ArrayList为例
ArrayList arrayList = new ArrayList();
arrayList.add("1");
arrayList.add("2");
arrayList.add("3");
insertBuilder.insert(0, arrayList);
System.out.printf("%s\n\n", insertBuilder);
}
}
有任何问题,欢迎指出.
网友评论