String的构造函数
String
有很多构造函数,不同种类的有不同的作用,接下来我们一个个看下去
- 1
public String() {
this.value = "".value;
}
初始化一个String
对象,使其表示一个空字符串序列,由于字符串的不可变性,这个方法其实是不必要的。
- 2
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
简单易懂,除非需要显式复制,否则这个方法也是不必要,因为字符串的不可变性。
- 3
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
依然很简单,不过要注意字符数组的后续修改不会影响新创建的字符串。
- 4
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= 0) {
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= value.length) {
this.value = "".value;
return;
}
}
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
这个方法是从字符数组中截取一段作为value
的值,这里面做了一些关于长度与角标的判断,另外,同样的,这里形参char[]
的改变与其之前所创建的String
对象已经没有关系了
- 5
public String(int[] codePoints, int offset, int count) {
if (offset < 0) { //简单的校验
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= 0) {
if (count < 0) { //简单的校验
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= codePoints.length) { //如果截取起点大于int数组长度,那么返回空字符串
this.value = "".value;
return;
}
}
// Note: offset or count might be near -1>>>1.
if (offset > codePoints.length - count) { //简单的判断
throw new StringIndexOutOfBoundsException(offset + count);
}
final int end = offset + count; //获取终点位置
// Pass 1: Compute precise size of char[]
int n = count; //由于Unicode的编码特点,字符串的真实长度并不是int数组的长度,用n这个变量来记录字符串的真实长度,下面的for循环就是在计算真正的长度
for (int i = offset; i < end; i++) {
int c = codePoints[i];
if (Character.isBmpCodePoint(c))//一个码元长度
continue;
else if (Character.isValidCodePoint(c))//两个码元长度,需要增加字符串长度
n++;
else throw new IllegalArgumentException(Integer.toString(c));
}
// Pass 2: Allocate and fill in char[]
final char[] v = new char[n];
for (int i = offset, j = 0; i < end; i++, j++) {
int c = codePoints[i];
if (Character.isBmpCodePoint(c))
v[j] = (char)c;
else
Character.toSurrogates(c, v, j++);
}
this.value = v;
}
这个方法涉及到Unicode编码的知识:
传入int作为参数,这个int是这个字对应的Unicode(16进制数)。每个最大65535 0xFFFF
public static final int MIN_CODE_POINT = 0x000000;
public static final int MAX_CODE_POINT = 0X10FFFF;
UTF-16中的基本单位是两个字节的码元,基本的码元范围是(0x0000-0xFFFF), UTF-16的字符映射范围是(U+0000,U+10FFFF),
当一个生僻字符需要使用0xFFFF以上的映射范围时,其需要使用两个码元(4Byte)进行表示. 其映射规则如下
第一个码元(前导代理)范围:0xD800 - 0xDBFF
第二个码元(后尾代理)范围:0xDC00 - 0xDFFF
有:(0xDBFF-0xD800+1)*(0xDFFF-0xDC00+1) === (0x10FFFF-0xFFFF)双射
所以(0xD800 - 0xDBFF)范围内的码元不能单独表示字符,其必须与后尾代理一起构成一个完整字符.
参考文档:https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/
public String(int[] codePoints, int offset, int count) {
if (offset < 0) { //简单的校验
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= 0) {
if (count < 0) { //简单的校验
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= codePoints.length) { //如果截取起点大于int数组长度,那么返回空字符串
this.value = "".value;
return;
}
}
// Note: offset or count might be near -1>>>1.
if (offset > codePoints.length - count) { //简单的判断
throw new StringIndexOutOfBoundsException(offset + count);
}
final int end = offset + count; //获取终点位置
// Pass 1: Compute precise size of char[]
int n = count; //由于Unicode的编码特点,字符串的真实长度并不是int数组的长度,用n这个变量来记录字符串的真实长度,下面的for循环就是在计算真正的长度
for (int i = offset; i < end; i++) {
int c = codePoints[i];
if (Character.isBmpCodePoint(c))//一个码元长度
continue;
else if (Character.isValidCodePoint(c))//两个码元长度,需要增加字符串长度
n++;
else throw new IllegalArgumentException(Integer.toString(c));
}
// Pass 2: Allocate and fill in char[]
final char[] v = new char[n];
for (int i = offset, j = 0; i < end; i++, j++) {
int c = codePoints[i];
if (Character.isBmpCodePoint(c))
v[j] = (char)c;
else
Character.toSurrogates(c, v, j++);
}
this.value = v;
}
这个方法涉及到Unicode编码的知识:
传入int作为参数,这个int是这个字对应的Unicode(16进制数)。每个最大65535 0xFFFF
public static final int MIN_CODE_POINT = 0x000000;
public static final int MAX_CODE_POINT = 0X10FFFF;
UTF-16中的基本单位是两个字节的码元,基本的码元范围是(0x0000-0xFFFF), UTF-16的字符映射范围是(U+0000,U+10FFFF),
当一个生僻字符需要使用0xFFFF以上的映射范围时,其需要使用两个码元(4Byte)进行表示. 其映射规则如下
第一个码元(前导代理)范围:0xD800 - 0xDBFF
第二个码元(后尾代理)范围:0xDC00 - 0xDFFF
有:(0xDBFF-0xD800+1)*(0xDFFF-0xDC00+1) === (0x10FFFF-0xFFFF)双射
所以(0xD800 - 0xDBFF)范围内的码元不能单独表示字符,其必须与后尾代理一起构成一个完整字符.
参考文档:https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/
- 6
public String(StringBuilder builder) {
this.value = Arrays.copyOf(builder.getValue(), builder.length());
}
public String(StringBuffer buffer) {
synchronized(buffer) {
this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
}
}
这里也体现了StringBuilder和StringBuffer的并发安全性。