1.今天来解析下常用的String类 , 由于源码太多,就解析几个重要的方法。见下面我自己定义的String类代码:
//final 不可被继承
final class MyString {
// 真正 存储 字符串的地方 , final 不可变
private final char value[];
// 指定 value 的从哪个位置起 算有效字符. 感觉没啥用
private final int offset;
// 字符串的长度
private final int count;
//为了不每次都计算hash值 , 缓存hash值,见hashCode方法
private int hash;
public MyString() {
this.offset = 0;
this.count = 0;
this.value = new char[0];
}
MyString(int offset, int count, char value[]) {
this.value = value;
this.offset = offset;
this.count = count;
}
// 第一次, 需要计算hash值,然后缓存到全局变量hash上, 后面 就直接拿,增加效率
public int hashCode() {
int h = hash;
if (h == 0) {
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++) {
h = 31 * h + val[off++];
}
hash = h;
}
return h;
}
// 字符串长度
public int length() {
return count;
}
// 字符串是否为空
public boolean isEmpty() {
return count == 0;
}
// 第几个位置的字符
public char charAt(int index) {
return value[index + offset];
}
// 循环遍历 真正的char数组 比每个char
public boolean equals(Object anObject) {
MyString anotherString = (MyString) anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
return false;
}
// 是否已 prefix开头
public boolean startsWith(MyString prefix, int toffset) {
char ta[] = value;
int to = offset + toffset;// 从哪个位置开始查找
char pa[] = prefix.value;
int po = prefix.offset;
int pc = prefix.count;
// Note: toffset might be near -1>>>1.
if ((toffset < 0) || (toffset > count - pc)) {
return false;
}
while (--pc >= 0) { // 直到prefix被遍历完
// 同位置 时的字符 比较 ,当有一个不同就代表不同了
if (ta[to++] != pa[po++]) {
return false;
}
}
return true;
}
// 截取 beginIndex 到 endIndex 的字符串 , 若截取的范围是0到自己的长度就返回自己 , 否则返回一个新的字符串
public MyString substring(int beginIndex, int endIndex) {
return ((beginIndex == 0) && (endIndex == count)) ? this
: new MyString(offset + beginIndex, endIndex - beginIndex,
value);
}
// 连接字符串(将str连接到后面), 如果被连接的字符串为空 , 则返回本身, 否则返回一个新的字符串
public MyString concat(MyString str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
// 构造一个可以存放这两个数组 的 字符数组
char buf[] = new char[count + otherLen];
// 将 value 拷贝到 buf里面(从buf的0位置开始)
getChars(0, count, buf, 0);
// 将 str 的value 拷贝到 buf (从buf 的count位置开始拷贝)
str.getChars(0, otherLen, buf, count);
return new MyString(0, count + otherLen, buf);
}
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
System.arraycopy(value, offset + srcBegin, dst, dstBegin, srcEnd
- srcBegin);
}
// 去除字符串首位的 空格, 如果没有就返回本身,否则返回一个新的字符串
public MyString trim() {
int len = count;
int st = 0;
int off = offset; /* avoid getfield opcode */
char[] val = value; /* avoid getfield opcode */
// 记录从前面开始不是空格的位置。 从val的前面开始找, <= 空格的 ,空格就是32 , 但
// 为啥要小于32呢?查看ASCII表,最小的就是32
while ((st < len) && (val[off + st] <= ' ')) {
st++;
}
// 与上面一样 , 只是从末尾开始
while ((st < len) && (val[off + len - 1] <= ' ')) {
len--;
}
// ((st > 0) || (len < count)) :代表前面或者后面有空格。]
// substring(st, len) :截取 不是空格的部分
return ((st > 0) || (len < count)) ? substring(st, len) : this;
}
/**
* 放入常量池 new String()构造的字符串 调用才有意义 先查找常量池中是否有相同Unicode的字符串常量,如果有,则返回其的引用,
* 如果没有,则在常量池中增加并返回当前引用。 常量池(constant
* pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。 它包括了关于类、方法、接口等中的常量,也包括字符串常量。
*/
public native String intern();
}
代码要认真一行一行看到位,就可以看懂,谢谢大家!祝大家元旦快乐!!
老生常谈:深圳有爱好音乐的会打鼓(吉他,键盘,贝斯等)的程序员和其它职业可以一起交流加入我们乐队一起嗨。我的QQ:657455400