java之AbstractStringBuilder类详解
AbstractStringBuilder类 |
位置:java.lang包中 |
声明:
abstract class
AbstractStringBuilderimplements Appendable, CharSequence
|
AbstractStringBuilder 类有abstract 修饰,可知它不能被实例化。 AbstractStringBuilder 类有两个子类:StringBuilder和StringBuffer。 |
字段 |
/** * The value is used for character storage. */ char value[]; /** * The count is the number of characters used. */ int count; |
构造器 |
1、无参构造器 AbstractStringBuilder() {
}
|
2、创建abstractstringbuilder实现类的对象时指定缓冲区大小为capacity。 AbstractStringBuilder(int capacity) { value = new char[capacity]; } 当子类StringBuilder或StringBuffer实例化时,会在构造器中调用此构造器。 |
扩充容量 |
void expandCapacity(int minimumCapacity) |
此方法有包访问权限,类中有多个方法会调用此方法,在容量不足时扩充容量。
|
源码: void expandCapacity(int minimumCapacity) { int newCapacity = (value.length + 1) * 2; if (newCapacity < 0) { newCapacity = Integer.MAX_VALUE; } else if (minimumCapacity > newCapacity) { newCapacity = minimumCapacity; } value = Arrays.copyOf(value, newCapacity); } 将缓冲区长度加1乘2的值赋予变量newCapacity, 然后将此值与指定的值比较,将较大值确定为缓冲区的新容量;然后调用Arrays类的copyof方法,此方法会创建一个新数组,然后将原数组中的字符全部复制进新数组中。 |
ensureCapacity(int minimumCapacity) |
public void ensureCapacity(int minimumCapacity) |
确保容量至少等于指定的最小值。如果当前容量小于指定值,则创建新数组,新数组的容量为指定值的两倍加2;如果当前容量不小于指定值,则直接不做处理。 |
源码: public void ensureCapacity(int minimumCapacity) { if (minimumCapacity > value.length) { expandCapacity(minimumCapacity); } } |
测试: StringBuffer s = new StringBuffer(); System.out.println("容量:" + s.capacity());// 容量:16 s.ensureCapacity(10); System.out.println("容量:" + s.capacity());// 容量:16 s.ensureCapacity(30); System.out.println("容量:" + s.capacity());// 容量:34 s.ensureCapacity(80); System.out.println("容量:" + s.capacity());// 容量:80 |
length() |
public int length() |
返回缓冲区中的代码单元数。 |
注意:此方法返回的并不是字符的数量,因为对于Unicode增补字符1个代码点对应2个代码单元。可以通过codePointCount方法获取字符数。 |
源码: public int length() { return count; } |
Unicode标量值测试: StringBuffer s = new StringBuffer(); System.out.println(s.append('a').append('b').length());// 2 System.out.println(s.codePointCount(0, s.length()));// 2 Unicode增补字符测试: StringBuffer s = new StringBuffer(); System.out.println(s.append('\ud800').append('\udc00').length());// 2 System.out.println(s.codePointCount(0, s.length()));// 1 |
capacity() |
public int capacity() |
返回数组value的容量。
|
源码: public int capacity() { return value.length; } |
测试: System.out.println(s.capacity());// 10 System.out.println(s.length());// 0 |
反转 |
public AbstractStringBuilder reverse() |
将字符序列反转。 |
问题:我们知道对于Unicode 标量值只需要1个char变量即可表示,但对于增补字符却需要2个char变量,反转时如何正确的处理这些字符? 查看reverse源码: public AbstractStringBuilder reverse() { boolean hasSurrogate = false; int n = count - 1; for (int j = (n - 1) >> 1; j >= 0; --j) { char temp = value[j]; char temp2 = value[n - j]; if (!hasSurrogate) { hasSurrogate = (temp >= Character.MIN_SURROGATE && temp <= Character.MAX_SURROGATE) || (temp2 >= Character.MIN_SURROGATE && temp2 <= Character.MAX_SURROGATE); } value[j] = temp2; value[n - j] = temp; } if (hasSurrogate) { // Reverse back all valid surrogate pairs for (int i = 0; i < count - 1; i++) { char c2 = value[i]; if (Character.isLowSurrogate(c2)) { char c1 = value[i + 1]; if (Character.isHighSurrogate(c1)) { value[i++] = c1; value[i] = c2; } } } } return this; } 可知此方法主要有两步: 1、用一个循环反转序列;并在每次循环时判断调换的两个字符是否有一个字符在\uD800和\uDFFF之间,如果有则置hasSurrogate的值为true。 2、若hasSurrogate的值为true,则进入第二个循环,调用Character类的isLowSurrogate和isHighSurrogate方法判断,将反转的增补字符再次反转,以此可确保字符的正确性。 |
添加 |
|||||
|
|||||
|
|||||
|
|||||
|
|||||
|
|||||
|
|||||
|
|||||
|
|||||
|
|||||
|
|||||
|
|||||
|
|||||
|
删除 |
public AbstractStringBuilder
delete(int start, int end)
|
删除字符序列中从start开始,end结束的子序列。 |
插入 |
|||||
|
|||||
|
|||||
|
|||||
|
|||||
|
|||||
|
|||||
|
|||||
|
|||||
|
|||||
|
|||||
|
|||||
|
获取索引 |
|||||
|
|||||
|
|||||
|
|||||
|
替换 |
public AbstractStringBuilder replace(int start, int end, String str) |
用字符串str替换原字符序列中从start开始,end结束的子序列。 |
部分代码: if (end > count) end = count; int len = str.length(); int newCount = count + len - (end - start); if (newCount > value.length) expandCapacity(newCount); System.arraycopy(value, end, value, start + len, count - end); str.getChars(value, start); count = newCount; return this; |
获取子序列 |
||||
|
||||
|
||||
|
调整空间 |
public void trimToSize() |
试图减少字符序列的存储。如果缓冲区是大于必要的保持其当前的字符序列,然后可调整到更加节省空间。 |
源码: public void trimToSize() { if (count < value.length) { value = Arrays.copyOf(value, count); } }
|
测试: StringBuffer sb = new StringBuffer("12345"); System.out.println("字符串:" + sb + ";sb容量:" + sb.capacity());// 字符串:12345;缓冲区大小:21 sb.trimToSize(); System.out.println("字符串:" + sb + ";sb容量:" + sb.capacity());// 字符串:12345;缓冲区大小:5
|
设置长度 |
public void setLength(int newLength) |
指定字符序列新长度为newLength。 |
源码: public void setLength(int newLength) { if (newLength < 0) throw new StringIndexOutOfBoundsException(newLength); if (newLength > value.length) expandCapacity(newLength); if (count < newLength) { for (; count < newLength; count++) value[count] = '\0'; } else { count = newLength; } }
|
测试: StringBuffer s = new StringBuffer("123456"); System.out.println("字符串:" + s + ";长度:" + s.length());// 字符串:123456;长度:6 s.setLength(3); System.out.println("字符串:" + s + ";长度:" + s.length());// 字符串:123;长度:3 s.setLength(9); System.out.println("字符串:" + s + ";长度:" + s.length());// 字符串:123 ;长度:9
|
获取字符 |
public char charAt(int index) |
返回指定索引处的代码单元。 |
注意:此方法返回的并不一定是字符,因为对于Unicode增补字符1个代码点对应2个代码单元。 |
源码: public char charAt(int index) { if ((index < 0) || (index >= count)) throw new StringIndexOutOfBoundsException(index); return value[index]; }
|
修改字符 |
public void setCharAt(int index, char ch) |
修改指定索引处(index)的代码单元为指定的代码单元(ch)。 |
源码: public void setCharAt(int index, char ch) { if ((index < 0) || (index >= count)) throw new StringIndexOutOfBoundsException(index); value[index] = ch; }
|
删除字符 |
public AbstractStringBuilder deleteCharAt(int index) |
删除字符序列中指定索引处的代码单元。 |
源码: public AbstractStringBuilder deleteCharAt(int index) { if ((index < 0) || (index >= count)) throw new StringIndexOutOfBoundsException(index); System.arraycopy(value, index + 1, value, index, count - index - 1); count--; return this; }
|
getChars |
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) |
源数组value从srcBegin开始,srcEnd结束的字符序列依次覆盖目的数组dst中从dstBegin开始的连续(srcEnd - srcBegin)个代码单元。 |
注意:覆盖的字符序列不能越界。 |
源码: public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) { if (srcBegin < 0) throw new StringIndexOutOfBoundsException(srcBegin); if ((srcEnd < 0) || (srcEnd > count)) throw new StringIndexOutOfBoundsException(srcEnd); if (srcBegin > srcEnd) throw new StringIndexOutOfBoundsException("srcBegin > srcEnd"); System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin); }
|
测试1: StringBuffer s = new StringBuffer("123"); char dst[] = { 'a', 'b', 'c', 'd' }; s.getChars(1, 2, dst, 2); System.out.println(dst);// ab2d 测试2: StringBuffer s = new StringBuffer("123"); char dst[] = { 'a', 'b', 'c', 'd' }; s.getChars(1, 4, dst, 2); System.out.println(dst); 打印: Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 4
|
codePointAt(int index) |
public int codePointAt(int index) |
返回指定索引处的字符(Unicode code point)。 |
源码: public int codePointAt(int index) { if ((index < 0) || (index >= count)) { throw new StringIndexOutOfBoundsException(index); } return Character.codePointAt(value, index); }
|
标量值测试: StringBuffer s = new StringBuffer(); s.append('1').append('2'); for (int i = 0; i < s.length(); i++) { System.out.println(s.codePointAt(i)); } 打印: 49 50 增补字符测试: StringBuffer s = new StringBuffer(); s.append('\ud800').append('\udc00'); for (int i = 0; i < s.length(); i++) { System.out.println(s.codePointAt(i)); } 打印: 65536 56320 从测试中可以看出当字符序列中都是标量值字符时,直接输出对应的码点;当有增补字符时,那么,当索引指向的是高代理项时,就会输出整个增补字符的码点,当索引指向的是低代理项时,就会返回对应代码单元的码点。 |
codePointBefore(int index) |
public int codePointBefore(int index) |
返回指定索引前的字符(Unicode code point)。 |
部分源码: return Character.codePointBefore(value, index);
|
标量值测试: StringBuffer s = new StringBuffer(); s.append('1').append('2').append('3'); for (int i = 0; i < s.length(); i++) { if (i == 0) continue; System.out.println(s.codePointBefore(i)); } 打印: 49 50 增补字符测试: StringBuffer s = new StringBuffer(); s.append('\ud800').append('\udc00').append('1'); for (int i = 0; i < s.length(); i++) { if (i == 0) continue; System.out.println(s.codePointBefore(i)); } 打印: 55296 65536 从测试中可以看出当字符序列中都是标量值字符时,输出指定索引处的码点;当有增补字符时,那么,当索引指向的是高代理项时,就会输出对应代码单元的码点;当索引指向的是低代理项时,就会返回整个增补字符的码点。 |
codePointCount(int beginIndex, int endIndex) |
public int codePointCount(int beginIndex, int endIndex) |
返回在指定的文本范围的Unicode代码点的数量。 |
源码: public int codePointCount(int beginIndex, int endIndex) { if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) { throw new IndexOutOfBoundsException(); } return Character.codePointCountImpl(value, beginIndex, endIndex - beginIndex); } 测试1: StringBuffer s = new StringBuffer("123123"); System.out.println(s.codePointCount(0, s.length()));// 6 测试2: StringBuffer s = new StringBuffer(); s.append('\ud800').append('\udc00'); System.out.println(s.codePointCount(0, s.length()));// 1 从测试中可知对于Unicode标量值1个代码点对应1个char,对于Unicode增补字符1个代码点对应2个char。 |
offsetByCodePoints(int index, int codePointOffset) |
public int offsetByCodePoints(int index, int codePointOffset) |
返回从给定的index处偏移codePointOffset个代码点的索引。 |
源码: public int offsetByCodePoints(int index, int codePointOffset) { if (index < 0 || index > count) { throw new IndexOutOfBoundsException(); } return Character.offsetByCodePointsImpl(value, 0, count, index, codePointOffset); } |
测试: StringBuffer s = new StringBuffer(); s.append('1').append('2').append('\ud800').append('\udc00').append('1'); System.out.println(s.offsetByCodePoints(0, 1)); System.out.println(s.offsetByCodePoints(0, 2)); System.out.println(s.offsetByCodePoints(0, 3)); 打印: 1 2 4
|
appendCodePoint(int codePoint) |
public AbstractStringBuilder appendCodePoint(int codePoint) |
添加指定代码点对应的字符。 |
源码: public AbstractStringBuilder appendCodePoint(int codePoint) { if (!Character.isValidCodePoint(codePoint)) { throw new IllegalArgumentException(); } int n = 1; if (codePoint >= Character.MIN_SUPPLEMENTARY_CODE_POINT) { n++; } int newCount = count + n; if (newCount > value.length) { expandCapacity(newCount); } if (n == 1) { value[count++] = (char) codePoint; } else { Character.toSurrogates(codePoint, value, count); count += n; } return this; }
|
标量值测试: StringBuffer s = new StringBuffer(); s.appendCodePoint(49); System.out.println(s); System.out.println(s.length()); 打印: 1 1 增补字符测试: StringBuffer s = new StringBuffer(); s.appendCodePoint(65536); System.out.println(s); System.out.println(s.length()); 打印:
|