String中方法的源码整理 String

String

String在Java中实际上是以字符数组的方式进行存储的,并且通过源码可以看出。

1
java复制代码char val[] = value;

在String中每次调用都是将它的value重新复制给另一个新的字符数组,所以我们不能更改它原本的值,而且value也不能被子类继承,所以String是不可更改的。

有一种情况String的值可以进行修改【反射】。后面在说

String类中的属性

1
2
3
4
5
6
7
8
9
10
11
java复制代码public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
//字符数组,存储字符串的值
private final char value[];
//字符串类型的hash值,默认是0;
private int hash;
//String类的序列化ID,通过ID来识别软件版本
private static final long serialVersionUID = -6849794470754667710L;

private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0];

}
1
2
3
4
5
6
7
8
java复制代码/*
*StringBuffer:线程安全的带缓存的String,可变的字符串
*/
String str = "abc"; //创建了一个对象

String str1 = new String("def");//创建了两个对象

str1 = str1 + str;//创建了一个"abcdef"字符串对象,底层使用了StringBuffer的append();
1
2
3
java复制代码//String str = "abc";
char data[] = {'a','b','c'};
String str == new String(data);

构造函数

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
34
35
java复制代码/*无参构造*/
//不能进行追加,删除等操作,只能进行覆盖操作
public String(){
this.value = "".value;
}

//将参数的value和hash值都直接赋值给新创建的对象
public String (String original){
this.value = original.value;
this.hash = original.hash;
}

//截取字符串的子串,substring就是调用此构造函数
public String(char value[]/*截取字符串的字符数组*/, int offset/*开始的位置*/, int count/*截取的长度*/){
if(offset < 0){
throws new StringIndexOutOfBoundsException(offset);
}
if(count <= 0){
//截取长度不能小于0
if(count < 0){
throws new StringIndexOutOfBoundsException(count);
}
//count == 0时就代表没有进行截取,返回传入的value值
if(offset <= value.length){
this.value = "".value;
return;
}
}
//如果offset超届抛出异常
if(offset > value.length - count){
throws new StringIndexOutOfBoundsException(offset+count);
}
//都没有问题的时候
this.value = Arrays.copyOfRange(value, offset, offset+count);
}

String类的方法

hashCode

获取字符串的hash码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
java复制代码//String中的hashCode
//在String中进行重写
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;
}

//Object中的hashCode
//看不见具体的实现方法,它自动给你返回一个hash值
public native int hashCode();

equals

字符串进行比较,看是否相等

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
java复制代码//Object中的equals
public boolean equals(Object obj){
return (this == obj) //比较内存值
}

//String中的equals
public boolean equals(Object anObject){
if(this == anObject){
return true;
}
//测试anObject是否是String的实例
if(anObject instanceof String){
//将anObject强制转换成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]){
//一旦有元素不同,就证明他们不是同一对象
return false;
}
i ++;
}
return true;
}
}
return false;
}

charAt

获取想要位置的字符

1
2
3
4
5
6
7
8
java复制代码public char charAt(int index){
if((index < 0) || (index >= value.length)){
//索引位置超出界限,抛出异常
throw new StringIndexOutOfBoudsException(index);
}
//返回索引位置的字符
return value[index];
}

substring

剪下一段字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
java复制代码public String substring(int beginIndex){
if(beginIndex < 0){
//超出界限异常
throw new StringIndexOutOfBoudsException(beginIndex);
}
//剪切的长度
int subLen = value.length - beginIndex;
//剪切的长度不能超过字符串的长度
if(subLen < 0){
throws new StringIndexOutOfBoudsException(subLen);
}
//如果index从0开始就返回字符串全部,不然就新建一个字符串返回
return (beginIndex == 0) ? this : new String(value,beginIndex,subLen);
}

indexOf

查找字符在字符串中的位置

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
java复制代码public int indexOf(int ch/*传入字符时自动转化为int*/){
return indexOf(int ch, int fromIndex/*开始查找的位置*/);
}
//进行重载
public int indexOf(int ch, int fromIndex){
final int max = value.length;
if(fromIndex < 0){
//如果输入错误的index那么让函数从头开始查找
fromIndex = 0;
} else if(fromIndex >= max){
//选择范围超出了界限
return -1;
}
//查找通用字符,在java中存储的值通常都是小于MIN的
//MIN_SUPPLEMENTARY_CODE_POINT = 0x010000
if(ch < Character.MIN_SUPPLEMENTARY_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);
}
}

replace

替换字符

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
java复制代码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;
}
}
//进行替换
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

去除字符串中两头的空格,在ASCII码中,空格是可见字符的最小值。

image-20210728145758913

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
java复制代码public String trim(){
int len = value.length;
int st = 0;//字符串的开始位置
char[] val = value;
//找到可见字符的起始位置
while((st < len) && (val[st] <= ' ')){
//遇见不可见字符则起始位置向后加
st ++;
}
//找到可见字符的结束位置
while((st < len) && val[len - 1] <= ' '){
//遇见不可见字符则结尾向前加
len --;
}
//将字符串从st开始到len结束进行剪切
return ((st > 0) || (len < value.length))/*最少有一个空格被解决*/ ? substring(st,len) : this/*没有空格被消除*/;
}

split

按照给定的规则将字符串分割成数组

image-20210728152854156

image-20210728152937214

image-20210728152956631

image-20210728153014483

image-20210728153034596

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
java复制代码public String[] split(String regex){
return split(regex, 0); //进行重载,从字符串头开始
}

public String[] split(String regex, int limit){
char ch = 0;
/*
*regex为一个字符时,这个字符不能为正则的元字符,例如"^$.+\\?{}[]"等
*regex是两个字符的时候并且第一个是'\'时,第二个不能时数字或字母
*/
if(((regex.value.length == 1 &&
".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1)/*regex为一个字符时,这个字符不能为正则的元字符*/ ||
(regex.length() == 2 &&
regex.charAt(0) == '\\' &&
(((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
((ch-'a')|('z'-ch)) < 0 &&
((ch-'A')|('Z'-ch)) < 0)) &&/*regex是两个字符的时候并且第一个是'\'时,第二个不能时数字或字母*/
(ch < Character.MIN_HIGH_SURROGATE ||
ch > Character.MAX_LOW_SURROGATE)){
int off = 0;
int next = 0;
//匹配的次数,没有设置时默认查询到字符串结束
boolean limited = limit > 0;
//存放结果的数组
ArrayList<String> list = new ArrayList<>();

while((next = indexOf(ch, off)) != -1/*查询regex在String中的位置,确认String中有regex的存在,等于this.indexOf(ch, off)*/){
if(!limited || list.size() < limit - 1){
//没有进行次数初始化,或者当前数组的大小小于规定的次数
//将不包含regex的子字符串放入数组中
list.add(substring(off,next));
//off直接到已经查到的regex位置加1,跳过现在的regex
off = next + 1;
} else {
//现在数组的大小已经等于limit - 1,只需要进行最后一次操作
list.add(substring(off, value.length));
off = value.length;
break;
}
}
if(off == 0){
//没有找到字符串中的regex
return new String[]{this};
}
if(!limited || list.size() < limit){
//传入的limit > 字符串中regex的次数,需要将剩余的部分添加到数组中
list.add(substring(off, value.length));
}
//构造结果
int resultSize = list.size();
if(limit == 0){
//没有传入参数或者传入的时0时,将list最后面的空数据删除掉
while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {
resultSize --;
}
}
//返回结果
String result[] = new String[resultSize];
return list.subList(0, resultSize).toArray(result);
}
return Pattern.compile(regex).split(this, limit);
}

如果没有使用第51行的代码的话将会造成下面的这个结果

1
2
3
java复制代码"boo:foo:boo".split("0",0)
-----------result--------------
{"b","",":f","",":b",""}

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%