Java 语言中 String 类用来代表字符串,相信对于 String 大家都再熟悉不过的了,这里就了解下 JDK 中怎么实现 String 类的。
阅读笔记:
1、String对象的值是一个常量,一旦创建后不能被改变。正式因为其不可变,所以它是线程安全地,可以多个线程共享。
2、String 类被声明为 final,说明它不能再被继承。同时它实现了三个接口,分别为 Serializable、Comparable 和 CharSequence。其中 Serializable 接口表明其可以序列化;
3、主要属性:
/** 用于存储字符串 */
private final char value[];
/** 缓存字符串对象的哈希值,默认值为0 */
private int hash;
/**用于排序的比较器 CaseInsensitiveComparator为内部类*/
public static final Comparator CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator();
/**
* seed value used for each alternative hash calculated.
* 用于计算每个备选哈希的种子值。 没搞明白 先不管
*/
private static final int HASHING_SEED;
4、内部类 CaseInsensitiveComparator
提供排序的比较器,实现了Comparator接口和compare方法,另外一个readResolve方法用于替换反序列化时的对象。
private static class CaseInsensitiveComparator
implements Comparator, java.io.Serializable {
// use serialVersionUID from JDK 1.2.2 for interoperability
public int compare(String s1, String s2) {
int n1 = s1.length();
int n2 = s2.length();
//取二者长度最小值
int min = Math.min(n1, n2);
//以最小值为最大循环次数开启循环比较
for (int i = 0; i
char c1 = s1.charAt(i);
char c2 = s2.charAt(i);
//如果字符不等
if (c1 != c2) {
c1 = Character.toUpperCase(c1);
c2 = Character.toUpperCase(c2);
// 如果字符的大写不等
if (c1 != c2) {
c1 = Character.toLowerCase(c1);
c2 = Character.toLowerCase(c2);
// 如果字符的小写不等
if (c1 != c2) {
// No overflow because of numeric promotion
return c1 - c2;
}
}
}
}
return n1 - n2;
}
}
判断了大写的情况还判断小写的原因是:由于自然语言的变幻莫测,有两种不同的Unicode字符具有相同的大写或小写的情况
5、构造器
没有参数的构造方法直接将空字符串的 value 进行赋值
public String() {
this.value = new char[0];
}
传入 String 对象的构造方法则将该对象对应的 value 和 hash 进行赋值。
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
构造方法传入 char 数组时,将数组数据复制为字符串
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
6、length() 得到字符的长度
public int length() {
return value.length;
}
7、isEmpty() 通过判断数组长度判断字符串是否为空
public boolean isEmpty() {
return value.length == 0;
}
8、 charAt(int index) 返回指定索引的char值 索引范围限制在 大于等于0小于字符串长度之间
public char charAt(int index) {
if ((index = value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return value[index];
}
9、codePointAt(int index) 获取字符串对应索引的 Unicode 代码点
public int codePointAt(int index) {
if ((index = value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return Character.codePointAtImpl(value, index, value.length);
}
10、codePointBefore(int index) 获取字符串对应索引的前一个 Unicode 代码点 实现和codePointAt一样 只是索引减一了
public int codePointBefore(int index) {
int i = index - 1;
if ((i = value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return Character.codePointBeforeImpl(value, index, 0);
}
11、codePointCount(int beginIndex, int endIndex) 用于得到指定索引范围内代码点的个数
public int codePointCount(int beginIndex, int endIndex) {
if (beginIndex value.length || beginIndex > endIndex) {
throw new IndexOutOfBoundsException();
}
return Character.codePointCountImpl(value, beginIndex, endIndex - beginIndex);
}
12、offsetByCodePoints(int index, int codePointOffset) 返回此 String 中从给定的 index 处偏移 codePointOffset 个代码点的索引
public int offsetByCodePoints(int index, int codePointOffset) {
if (index value.length) {
throw new IndexOutOfBoundsException();
}
return Character.offsetByCodePointsImpl(value, 0, value.length,
index, codePointOffset);
}
13、getChars(char dst[], int dstBegin) 用于获取字符串对象指定范围内的字符到目标 char 数组中
void getChars(char dst[], int dstBegin) {
System.arraycopy(value, 0, dst, dstBegin, value.length);
}
14、getBytes 获取字节码数组
15、equals
用于比较两字符串对象是否相等,如果引用相同则返回 true。否则判断比较对象是否为 String 类的实例,是的话转成 String 类型,接着比较编码是否相同
16、contentEquals
比较字符串之间内容是否相等
如果为 AbstractStringBuilder 实例化出来,是的话表示它为 StringBuilder 或 StringBuffer 对象。
如果为 StringBuffer 对象,说明它是线程安全的,需要做同步处理,调用nonSyncContentEquals方法。
如果为 StringBuilder 对象,它是非线程安全的,直接调用nonSyncContentEquals方法。
如果为 String 对象,则调用equals方法比较。
接下去的逻辑属于 CharSequence 对象时的逻辑。如果长度不相等直接返回 false。
17、equalsIgnoreCase 对比字符串是否相等,而且是忽略大小写。
18、compareTo/compareToIgnoreCase(忽略大小写)
按字典顺序比较两个字符串。该比较基于字符串中各个字符的 Unicode 值。按字典顺序将此 String 对象表示的字符序列与参数字符串所表示的字符序列进行比较。如果按字典顺序此 String 对象位于参数字符串之前,则比较结果为一个负整数。如果按字典顺序此 String 对象位于参数字符串之后,则比较结果为一个正整数。如果这两个字符串相等,则结果为 0;compareTo 只在方法 equals(Object) 返回 true 时才返回 0。
19、regionMatches 检测指定区域字符串是否相等
20、startsWith 检测字符串是否以某个前缀开始,并且可以指定偏移。
21、endsWith 检测是否以某个字符串结尾,间接调用startsWith方法即可实现。
22、hashCode 返回字符串对象的哈希值,如果已经有缓存了则直接返回,否则就计算哈希值。
23、indexOf 用于查找字符串中第一个出现某字符或字符串的位置
有多种方法参数比如:可传入 int 类型,也可传入 String 类型,另外还能传入开始位置
24、lastIndexOf 返回指定字符在此字符串中最后一次出现处的索引 和indexOf类似的实现
25、substring 用于获取字符串的指定子字符串。有两个方法,一个是只传入开始索引,第二个是出传入开始索引和结束索引。
26、subSequence 等同于substring 方法 只是返回的类型不一样 这个返回的是CharSequence类型
27、concat 将指定的字符串参数连接到字符串上
28、replace 用于替换字符串中指定的字符
29、split 用于切分字符串,实现中首先会判断能不能不用正则引擎,如果可以则直接切分,否则采用正则引擎切分。
30、join (A (String), B (String[]));
ps:
在指定 String 数组B的每个元素之间串联指定的分隔符 A,从而产生单个串联的字符串
string [] tmpStr=;
string join = string.join(“|“, tmpStr);
此时jn=”abc|def|ghi”;
31、toLowerCase 将字符串成转成小写、toUpperCase 将字符串成转成大写
32、trim 用于删除字符串的头尾空白符
33、toString 返回字符串 直接返回this
34、toCharArray 将字符串转成 char 数组
35、format 格式化字符串
36、valueOf 将传入的对象转成 String 对象,可传入多种类型参数
Objet 时,为空则返回”null”字符串,否则obj.toString()。
char 数组时,直接new 一个 String 对象。
boolean 时,返回”true” 或 “false”字符串。
char 时,优先尝试转成 Latin1 编码的 String 读,否则用 UTF16。
int 时,Integer.toString(i)。
long 时,Long.toString(l)。
float 时,Float.toString(f)。
double 时,Double.toString(d)。
37、 public native String intern(); 标记了 native 的本地方法
字符串对象调用intern方法会先检查池中是否已经存在该字符串的标准对象,如果存在则直接返回标准对象,如果不存在则会往池中创建标准对象并且返回该对象。
可以在有大量重复字符串的场景下使用 以用来达到优化内存的效果
ps:100w的字符串对象里面有70w重复的对象 使用这个 可以把字符串对象数量缩小到30w
String这个类可以说是我们java开发者使用得最为频繁的类之一了,源码jdk1.7版本就有3000多行非常庞大精细,本文只是粗浅的阅读笔记 大家可以跟着源码仔细研读 相信会有更大的收获
领取专属 10元无门槛券
私享最新 技术干货