学习理解String的源代码
package java.lang;
代码块一
public final class Stringimplements Comparable<String>, CharSequence {// 1. 核心底层数组:存字符串每个字符private final char[] value;// 2. 哈希值缓存,默认0private int hash;// 空参构造:创建空字符串public String() {this.value = new char[0];}// 传入字符串构造方法public String(String original) {this.value = original.value;this.hash = original.hash;}
1.类声明
public final class Stringimplements Comparable<String>, CharSequence
1.public:公共类,项目任何地方都能用
2.final:不能被继承,防止别人篡改字符串底层
3.Comparable
4.CharSequence:字符序列规范,属于字符类型
2 核心成员变量
// 1. 底层存储内容
private final char[] value;// 2. 哈希缓存
private int hash;
① private final char[] value
·字符串真正存数据的地方
·你写 abc,本质就是:['a','b','c']
·final:数组地址不能改 → 字符串不可变根源
·private:外面拿不到,安全
② private int hash
·用来存哈希值,默认初始值 = 0
·作用:算一次存起来,下次直接用,提高速度
3 空构造方法
public String() {this.value = new char[0];
}
·创建空字符串 ""
·底层给一个长度为 0 的空字符数组
4 拷贝构造(重点)
public String(String original) {this.value = original.value;this.hash = original.hash;
}
String s = new String("abc");
·直接复用传入字符串的 value 数组
·不复制数据,节省内存
代码块二
// 获取字符串长度public int length() {return value.length;}// 判断是否为空字符串public boolean isEmpty() {return value.length == 0;}// 根据下标获取单个字符public char charAt(int index) {if ((index < 0) || (index >= value.length)) {throw new StringIndexOutOfBoundsException(index);}return value[index];}
5 length () 方法
public int length() {return value.length;
}
·字符串长度 = 底层字符数组长度
·直接返回数组长度
6 isEmpty () 判断是否为空
public boolean isEmpty() {return value.length == 0;
}
·数组长度为 0 → 就是空字符串 ""
7 charAt () 根据下标取字符
public char charAt(int index) {if ((index < 0) || (index >= value.length)) {throw new StringIndexOutOfBoundsException(index);}return value[index];
}
·先判断下标是否越界
·越界直接报错
·没越界,直接返回数组对应位置字符
代码块三
// 重点:比较字符串内容public boolean equals(Object anObject) {// 1. 同一个对象,直接trueif (this == anObject) {return true;}// 2. 判断是不是String类型if (anObject instanceof String) {String anotherString = (String) anObject;int n = value.length;// 3. 长度不一样,直接falseif (n == anotherString.value.length) {char[] v1 = value;char[] v2 = anotherString.value;int i = 0;// 4. 逐个字符对比while (n-- != 0) {if (v1[i] != v2[i])return false;i++;}return true;}}return false;}// 重点:计算哈希值 + 缓存public int hashCode() {int h = hash;// 如果没计算过(h=0),开始计算if (h == 0 && value.length > 0) {char[] val = value;// 计算公式:h = 31 * h + 字符编码for (int i = 0; i < value.length; i++) {h = 31 * h + val[i];}hash = h; // 缓存保存,下次直接用}return h;}
8 equals () 源码
public boolean equals(Object anObject) {// 1. 判断是不是同一个对象(地址一样)if (this == anObject) {return true;}// 2. 判断是不是 String 类型if (anObject instanceof String) {String anotherString = (String) anObject;int n = value.length;// 3. 长度不同直接不相等if (n == anotherString.value.length) {char v1[] = value;char v2[] = anotherString.value;int i = 0;// 4. 逐个字符对比while (n-- != 0) {if (v1[i] != v2[i])return false;i++;}return true;}}return false;
}
执行流程:
this == anObject:地址相同 → 直接 true
不是 String 类型 → 直接 false
长度不一样 → 直接 false
一个一个字符对比
全部一样才返回 true
总结:
== 比地址
equals 比内容
9 hashCode () 哈希方法
public int hashCode() {int h = hash;// 如果没算过(h=0)并且字符串不为空if (h == 0 && value.length > 0) {char val[] = value;// 哈希计算公式for (int i = 0; i < value.length; i++) {h = 31 * h + val[i];}hash = h; // 把算好的值缓存保存}return h;
}
1.h =hash 先读取缓存
2.第一次使用 hash=0,进入计算
3.公式:
h=31*h+当前字符编码
4.算完赋值给hash缓存
5.下次调用直接拿缓存,不用重算
代码块四
// 截取字符串public String substring(int beginIndex) {return new String(value, beginIndex, value.length - beginIndex);}// 字符串拼接public String concat(String str) {int len = value.length;int otherLen = str.length();char[] buf = new char[len + otherLen];System.arraycopy(value, 0, buf, 0, len);System.arraycopy(str.value, 0, buf, len, otherLen);return new String(buf);}// 返回自身字符串public String toString() {return this;}
}
10 截取字符串 substring ( )
public String substring(int beginIndex) {return new String(value, beginIndex, value.length - beginIndex);
}
new String( char[] 原数组, int 起始下标, int 截取长度 )
·value
就是当前字符串底层的 char[] 原字符数组
·beginIndex
截取开始的位置(从第几个字符开始切)
·value.length - beginIndex
总长度 − 开始位置 = 要截取的字符个数
1.它不会动原来的字符数组 value
2.而是 new 一个全新的 String
3.把截取的内容放进新字符串里
11.字符串拼接 concat ( )
public String concat(String str) {int len = value.length; // 原来字符串长度int otherLen = str.length(); // 要拼接的字符串长度char[] buf = new char[len + otherLen]; // 创建一个【新数组】System.arraycopy(value, 0, buf, 0, len); // 复制原字符串System.arraycopy(str.value, 0, buf, len, otherLen); // 复制拼接字符串return new String(buf); // 返回【新字符串】
}
1.先算总长度 = 原来长度 + 要拼接的长度
2.新建一个字符数组(更大的)
3.把两个字符串都复制进去
4.最后 new 一个新 String
11.toString( )
String 本身就是字符串,直接返回自己。
