String源码解析


接下来我们进行Sting的学习,这个类算是很常用的。

String继承了三个接口:

1
public final class String implements java.io.Serializable, Comparable<String>, CharSequence{}

Serializable接口只是做一个标识,Comparable接口是赋予了String比较的能力,CharSequence接口则是对String内部的Char[]操作提供方便的参数。

1
2
3
4
5
/** The value is used for character storage. */
private final char value[];

/** Cache the hash code for the string */
private int hash; // Default to 0

从这里可以看出String内部其实是char数组

String有大量的构造方法,都是调用了其他工具类中的方法,比如Arrays.copyOf()、Arrays.copyOfRange()等等。

本来想一一介绍,但是看了一圈觉得并没有这个必要,我就挑几个比较特别的说说吧。

1
2
3
4
5
6
7
8
9
10
public static String join(CharSequence delimiter, CharSequence... elements) {
Objects.requireNonNull(delimiter);
Objects.requireNonNull(elements);
// Number of elements not likely worth Arrays.stream overhead.
StringJoiner joiner = new StringJoiner(delimiter);
for (CharSequence cs: elements) {
joiner.add(cs);
}
return joiner.toString();
}

join()方法是在JDK1.8之后新加的,他的作用如下:

1
System.out.println(String.join(",","123","123"));//print: 123,123

这个函数可以方便我们进行数据展示的时候免于出现一连串的“”+””+…+””的蹩脚操作,也避免了删除最后一个字符的操作,他的内部实现其实是StringBuilder,即能够线程安全的展示数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public boolean equals(Object anObject) {
if (this == anObject) {//比较地址
return true;
}
if (anObject instanceof 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) {//循环比较value
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}

public int hashCode() {
int h = hash;
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;
}

equals本身没什么好说的,但是这个hashCode有点厉害,这个散列值为什么要这么计算请自行百度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//这里只说int型参,这个int是Unicode code,不是位置。
public int indexOf(int ch, int fromIndex) {
final int max = value.length;
if (fromIndex < 0) {
fromIndex = 0;
} else if (fromIndex >= max) {
// Note: fromIndex might be near -1>>>1.
return -1;
}

if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
// handle most cases here (ch is a BMP code point or a
// negative value (invalid code point))
final char[] value = this.value;
for (int i = fromIndex; i < max; i++) {
if (value[i] == ch) {
return i;
}
}
return -1;
} else {
return indexOfSupplementary(ch, fromIndex);
}
}

例如:

1
2
String str = "abc";
System.out.println(str.indexOf(98));// 1

indexOf(String str)用来返回字符所在位置的下标。

1
2
3
public String substring(int beginIndex);
public String substring(int beginIndex, int endIndex);
public CharSequence subSequence(int beginIndex, int endIndex);

substring方法用来分割字符串,最终实现都是重新new一个String:

1
new String(value, beginIndex, subLen)

equalsIgnoreCase也比较有用,用于不区分大小写比较的情况

1
2
3
4
5
6
public boolean equalsIgnoreCase(String anotherString) {
return (this == anotherString) ? true
: (anotherString != null)
&& (anotherString.value.length == value.length)
&& regionMatches(true, 0, anotherString, 0, value.length);
}

format是非常有用的一个方法,尤其你自己封装持久层时,简直是神器!支持的转换符有:

转换符 描述 转换符 描述
%s 字符串类型 %c 字符类型
%b 布尔类型 %d 十进制整数类型
%x 十六进制整数类型 %o 八进制整数类型
%f 浮点类型 %a 十六进制浮点类型
%e 指数类型 %g 通用浮点类型
%h 散列码类型 %% 百分比类型
%n 换行符 %tx 时间日期类型
1
2
3
public static String format(String format, Object... args) {
return new Formatter().format(format, args).toString();
}

intern方法用来将String对象加入常量池并返回引用,在循环、递归有限集合中灰常有用!

1
public native String intern();

-------------本文结束,感谢您的阅读-------------

本文标题:String源码解析

文章作者:饭饭君~

发布时间:2018年12月03日 - 16:54

最后更新:2019年04月23日 - 10:51

原始链接:https://yangcf.github.io/2018/12/03/String源码解析/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

如果我的文章有帮助到你,欢迎打赏~~
0%