类的定义
使用了final关键字修饰,因此不可被继承。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
常量的定义
//采用char型数组存储,jdk1.9后是采用byte型数组
private final char value[];
//缓存字符串的hash code
private int hash; // Default to 0
//序列化ID
private static final long serialVersionUID = -6849794470754667710L;
private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0];
构造函数
////通过一个String初始化,根据注释解释只是为了复制一样的字符串的值构造函数
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
//通过一个char型数组参数,初始化
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
//offset 偏移量
//count 复制的字符个数
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);
}
//传入代码点来构造String对象
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) {
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;
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;
}
//通过Byte型数组初始化
public String(byte bytes[], int offset, int length, String charsetName)
throws UnsupportedEncodingException {
if (charsetName == null)
throw new NullPointerException("charsetName");
checkBounds(bytes, offset, length);
this.value = StringCoding.decode(charsetName, bytes, offset, length);
}
关于代码点的补充知识
Unicode字符集
Unicode 就是给计算机中所有的字符各自分配一个代号。Unicode是属于编码字符集(CCS)的范围。Unicode所做的事情就是将我们需要表示的字符表中的每个字符映射成一个数字,这个数字被称为相应字符的码点(code point)。例如“严”字在 Unicode 中对应的码点是 U+0x4E25。
字符编码
为了便于计算的存储和处理,现在我们要把哪些纯数学数字对应成有限长度的比特值了。最直观的设计当然是一个字符的码点是什么数字,我们就把这个数字转换成相应的二进制表示,例如“严”在 Unicode 中对应的数字是 0x4E25,他的二进制是100 1110 0010 0101,也就是严这个字需要两个字节进行存储。按照这种方法大部分汉字都可以用两个字节来表示了。但是还有其他语系的存在,没准儿他们所使用的字符用这种方法转换就需要 4 个字节。这样问题又来了到底该使用几个字节表示一个字符呢?如果规定两个字节,有的字符会表示不出来,如果规定较多的字节表示一个字符,很多人又不答应,因为本来有些语言的字符两个字节处理就可以了,凭什么用更多的字节表示,多么浪费。
代码点(code point):针对Unicode编码概念的,编码字符集每个字符对应一个编号,这个编号可以理解为代码点,采用16进制。
代码单元(Code Unit):是指一个已编码的文本中具有最短的比特组合的单元。对于 UTF-8 来说,
码元是 8 比特长;对于 UTF-16 来说,码元是 16 比特长。
总结
- String类的构造函数,通过char型数组初始化时,主要采用了
Arrays.copyOf
函数。会创建一个新的数组,然后通过System.arraycopy
复制到新数组上并返回。
public static char[] copyOf(char[] original, int newLength) {
char[] copy = new char[newLength];
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
} Math.min(original.length, newLength)); return copy;}
因此System.arraycopy
要比Arrays.copyOf
效率高。System.arraycopy的底层代码是native方法,调用的c语言代码实现。
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
- 通过byte型数组初始化时,会调用
decode
方法进行解码,判断参数charsetName是否为Null,如果为Null采用ISO-8859-1编码方式,否则采用指定方式。ISO-8859-1的别名也叫latin-1,采用单字节编码,能更节省内存。