JDk源码阅读之String
1.String的定义
String表示字符串,是一个常量。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence,
Constable, ConstantDesc {
实现了serializable接口和comparable接口,并且是被final修饰的。所以String类是不可以被继承的。
2.String的量的定义
private final byte[] value;
//储存读入
private final byte coder;
private int hash;
//缓存字符串的hash值
private boolean hashIsZero;
private static final long serialVersionUID = -6849794470754667710L;
static final boolean COMPACT_STRINGS;
3.String的构造
public String() {
this.value = "".value;
}
/*
无参构造器,生成的是一个"",空字符,并不是null
*/
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
//offset表示第一个被截取的字符在数组value[]中的下标,count表示从此字符开始向后截取的字符的数量
//将value[]数组按照传入的下标和指定的截取数组数据的数量进行截取,并且创建一个内容为此的string对象
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;
}
}
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
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;
}
}
if (offset > codePoints.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
final int end = offset + count;
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));
}
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;
}
4.String的方法
equals:判断两个字符串是否相等
public boolean equals(Object anObject) {
if (this == anObject) {
//判断该对象是不是本对象
return true;
}
if (anObject instanceof String) {
//判断该对象的类型是不是String类型的
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
//判断两个字符的长度是否相同
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
//不相等直接返回true
return false;
i++;
}
return true;
}
}
return false;
}
compareTo:按字典序比较两字符串大小
public int compareTo(String anotherString) {
//自身对象字符串长度len1
int len1 = value.length;
//被比较对象的字符串长度len2
int len2 = anotherString.value.length;
//取两个字符串长度的最小值lim
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
//从value的第一个字符开始到最小长度lim处为止,如果字符不相等,返回自身(对象不相等处字符-被比较对象不相等字符)
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
//如果前面都相等,则返回(自身长度-被比较对象长度)
return len1 - len2;
}
concat:连接两字符串
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true);
}
replace:用新字符代替旧字符
public String replace(char oldChar, char newChar) {
//新旧值先对比
if (oldChar != newChar) {
int len = value.length;
int i = -1;
char[] val = value;
while (++i < len) {
if (val[i] == oldChar) {
break;
}
}
//i即为要替换的字符的位置
if (i < len) {
char buf[] = new char[len];
for (int j = 0; j < i; j++) {
buf[j] = val[j];
}
while (i < len) {
char c = val[i];
buf[i] = (c == oldChar) ? newChar : c;
i++;
}
return new String(buf, true);
}
}
return this;
}
trim:去掉字符串前后的空格
public String trim() {
int len = value.length;
int st = 0;
char[] val = value; /* avoid getfield opcode */
//找到字符串前段没有空格的位置
while ((st < len) && (val[st] <= ' ')) {
st++;
}
//找到字符串末尾没有空格的位置
while ((st < len) && (val[len - 1] <= ' ')) {
len--;
}
//如果前后都没有出现空格,返回字符串本身
return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
}
看源码我们可以看到,实际上去掉不只是空格,而是所有ASCALL码小于空格的符号。
5.总结
以上不是String类中的所有,还有许多的空缺,例如HashCode。对于Hashcode我还了解的不够深入,因此在这留出。
不同的JDK版本之间的源码之间或多或少之间纯在区别,之后也可以将不同版本之间的JDK源码放在一起比对,看看有什么不同,为什么不同。