首先来看String类,这是Java开发者最常用的一个类,也是最常用的引用类型。
先来看String类的修饰符和实现的接口:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
String类成员变量中有一个char数组,来表示String的"值",这种写法很明显表明这段代码的作者是个多年经验的C程序员,C语言里字符串用char数组表示,而且[]在变量名的后面。
private final char value[];
String类的成员变量中还有一个很有意思的东西:
<pre name="code" class="java">private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0];
这个数组所在的类暂时先不考虑,这个成员变量上面的注释是这么写的:String类是序列化流协议中的一个特殊实现,一个String实例最初以TC_String格式写入到ObjectOutputStream中,String由DataOutput.writeUTF写成的,一个新的句柄生成后指向流中的String实例的所有未来引用。我查了一下,这个类是用来声明可序列化字段的类,我理解这个变量就是这个数组用来存句柄,也就是标识String实例的整数值,但是这个数组目前是final的且长度为0,估计是目前尚未开发但以后会起作用的成员变量。
不纠结这个了,接下来看构造方法,有很多构造方法下面逐一解释一下:
<pre name="code" class="java">public String() {
this.value = new char[0];
}
这个无参的构造方法将value这个char数组初始化为一个长度为0的char数组,换句话说就是一个空字符串。
<pre name="code" class="java">public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
这个构造方法传入一个String变量作为唯一参数,构造方法内将这个参数的value也就是char数组传给本String类对象的value,也就是实现了值的传递,接下来又传递了参数的hash值,也就是将参数的索引也传给了本对象。
<pre name="code" class="java">public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
这个构造方法传入一个char数组,然后将char数组通过数组工具类的拷贝方法全部拷贝到本类的value属性,也就是只复制了值。
<pre name="code" class="java">public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
// 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);
}
这个构造方法传入三个参数,一个是char数组,一个是要复制的数组的起点下标,另一个是要复制的数组的长度。如果下标和长度都小于0,那么会出现异常。这个构造方法实现的是将从传入的char数组中的指定下标开始复制该char数组的count个元素到本对象的value中
<pre name="code" class="java">public String(int[] codePoints, int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
// 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;
}
这个构造方法较长,实际上很简单就是通过传入一个int数组,这个数组里存的是ASC码,然后后两个参数和上面那个构造方法的后两个参数一样,都是取下标和长度,然后把int数组中的指定元素以ASC码的形式取出来转换成字符再拼接,举个例子:
<pre name="code" class="java">String s=new String(new int[]{56,57,58},0,2);
最后s的值是89,因为取的是int数组里的第1位开始后的两位,也就是将ASC码中的56、57转换为字符拼接,也就是89。
</pre><pre name="code" class="java">下一篇继续写String类的源码分析