1.
首先我们可以看到是final 修饰的,不能被继承,只要被创建就不能再修改,所有我们平时看似修改实际上都是重新建了一个新的字符串。然后他实现了 Serializable接口,序列化不多赘述,Comparable 允许比较(按照ASCII码比较),CharSequence 博主第一次见,博主查阅了一下这是一个可读的字符序列,说的也很抽象。博主后来琢磨了一下,可以这样理解,这个接口提供了对char字符序列的读取。
2.
这边三个成员变量:value[] 用于存储字符,hash 用于存储该sting实例的hashCode默认为SerialVersionUID序列号
3.
这里有一个普ObjectStreamField,final类型的变量,博主看了一下翻译,String 类在序列化到流中处理的时候是特殊的,这个是专门用来存放流的。
4.String 构造函数
划横线的已经不推荐使用了,这边不再赘述
第一个构造函数,没什么特殊的,实际上该构造函数并不是必须的,因为String 类是final修饰的,不可变
第二个构造函数,直接将所需的字符串传入即可
第三个构造函数,传入字符的数组,我们可以发现他的实现很有意思,他是将字符数组整个复制过去了,这样做的目的是,复制过去之后,老的数组如果变更,就不会影响到复制过去的数组
第四个构造函数,在字符数组中从offset个开始截取count个,底层实现也是复制Arrays的形式
这边也是也是一个构造函数,中间做了一次判断,博主没有看懂,有看懂的小伙可以留言,最后通过复制的形式返回
这里几个构造函数我们放一起讲,都是用指定的字节数组来构造新的String。没有指定解码格式的会使用平台默认的编码来解码,有指定的则使用指定的编码。
此构造方法是将字符串缓冲区的字符序列分配到字符串中,地城使用Arrays 复制,值得一提的是,使用了synchronized 将改字符串缓存区的内容锁住了。
该构造方法使用类似上一个方法,只是将缓冲区的变成了字符串构建器
该构造函数,多一个是否分享的参数。
5.
校验初始值和长度是否小于0,校验下标是否越界
6.
返回字符串的长度
7.
判断字符串是否为空
8.
获取字符串指定位置的字符
9.
获取指定位置的Unicode代码点 ,方法不常用
10.
获取指定位置之前的Unicode代码点 (不常用)
11.
返回两个字符串之间的Unicode代码点数量(不常用)
12.
指定Unicode代码点,进行偏移 (不常用)
13.
将字符串中的字符复制到目标字符数组中。
14.
第一个方法是使用命名的字符集将String编码为字节序列,然后存储到新的字节数组中,第二个方法是使用指定的charset 将string 编码为一个字节序列,将结果存储到新的字节数组中。第三个方法直接按照平台默认的字符集将string编码为字节序列,然后存储到行的字节数组中。
15.
比较两个字符串是否相等的方法,首先用 instanceof 判断这个字符串是不是属于String,如果是就将这个字符串对象转成字符串,然后比较两个字符串的长度,如果长度也一样那个开始遍历这个两个char数组的每一个元素,如果全部一致,则判定这两个字符串一致。
16.
这里我们放三个方法,第一个是将字符串与stringBuffer 比较,后者是将字符串与charsequence进行比较,第三个我们先别看,先看stringbuffer 从源代码可以看出它,实际上底层调用的是 第二个方法,只是将stringbuffer进行了charsequence 强转,重点关注第二个方法的源代码,首先是做了判断,它是一层一层下来的,首先如果它属于AbstractStringBuilder,进一步判断是不是StringBuffer 如果是则加锁,加锁的目的是房子在比较过程中,stringBuffer被其他线程影响,这里可以看到真正比较的是我们的截图中的第三个方法,其实很简单,先判断长度是不是一样,如果一样在将数组中的元素一个个拿出来作比较,在回到上面,如果入参只是一个String 的话,就调用我们之前的equals方法即可作出比较,再往下,如果连string都不是,就直接把他charAt一下,遍历数组一个个做比较,这里其实我们可以看到,他在做一些判断之前都是先判断长度,这个实际上也算是一个技巧,在做一些判断是现比较一下长度,如果连长度都不一样的话,就不往下做比较了,节约时间。
17.
此方法是忽略大小写比较字符串,主要涉及到regionMatches方法,看底层可以知道如果是忽略大小写,是统一转成大写进行比较的。
18.
比较字符串,需要注意的是他返回的是int类型,首先比较的是第一位的ASCII码,如果第一位相同,比较第二位,一次类推,最后返回两者的之差,值得注意的是,如果两个字符串长度不一样,这种比较方式只比到最短的位置。如果比到这个最短位置还没有必出结果,则直接将这两个字符串长度做差。
19.
忽略大小写比较,没什么特别的全部转成小写只有比较。
20.
第二张截图不多说了,调的就是第一张截图的东西,首先这个方法,是查看字符串是否以prefix 前缀开头,第二个参数是从哪个位置开始。没什么特别的,就是和前缀一个个比过去的,一旦不一致就弹出false。
21.
没什么特别的,归根结底还是调用的startsWith的方法,第二个参数把需要计算的位置算出来了
22.
计算hashcode的方法, 哈希代码计算公式:s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1],使用int算术,其中s[i]是字符串的第i个字符,n是字符串的长度,^表示取幂。(空字符串的哈希值为零)
23.
从指定位置查看要查询的int第一次出现的位置,先做了一个判断其实位置是否大于字符串最大长度,如果是则直接返回-1,这边还做了一个判断MIN_SUPPLEMENTARY_CODE_POINT,如果小于这个,则直接遍历比较,返回第一个相同的值,如果不同则调用博主截图的第三个方法,indexOfSupplementary,比较中有两个条件,必须都相同。
24.
此方法与上述方法类似,不在赘述。就是反了一下
25.
查看字符串在该字符串中第一次出现的位置,一层套一层,主要就看最后一个截图的方法,看上去漫长其实并不复杂,就是不断的循环作比较。
26.
这个是从后往前找,和上面方法一个套路,不在赘述。
27.
subString 截取字符串,归根结底还是落到String 的一个构造方法上,整个字符串进行截取。没什么特殊的,值得注意的是,如果开始位置是0,结束位置刚好是最后一个位置,那么直接返回改字符串,反之才会重新new一个,这里可能就涉及到指向内存的问题。
28.
底层还是调用的subString方法。
29.
把传进来的字符串拼接在目标字符串后面,可以看到底层是采用的还是array的copyof。
30.
replace替换方法,如果两个一样则不替换,没有new 新的而是把原来的返回回去了,
31.
基于正则的匹配。
32.
查看这个string是否包含指定的字符,实际上就会indexOf 方法
33.
通过正则查询指定的字符串,替换第一个字符串。
34.
通过正则查找,全部替换与上面方法类似。
35.
替换从字符串开始到结束,例如,在字符串“aaa”中用“b”替换“aa”将导致“ba”而不是“ab”
36.
split切割字符串,底层是使用indexOf.可以发现很多方法都依赖于indexOf方法。
37.
组合字符串:
String message = String.join("-", "Java", "is", "cool");
// message returned is: "Java-is-cool"
这的注意的是入参的方法,楼主第二次见到这种写法,第一次是在go的语法中,没想到java也可以这样写。值得注意的是,里面用到了一个jdk8中的新类StringJoiner。拼接字符串的时候这个类性能十分突出。
38.
所有文字转小写,参数这个locale 包含了语言之类的信息,值得一提的是 可以发现里面有个scan:{} 代码块,楼主第一次见这个东西,查了一下就是一个普通的标签,和break scan 对应。可以看到底层调用的是 Character.toLowerCase()方法。此方法与后面toUpperCase 对应,后面不再赘述。
39.
去除字符串前后的空格。底层使用subString 将整个不含空格的部门截出来。
40.
toString方法返回他自己本身。
41.
将字符串转化为字符数组。,采用arraycopy的方式。
42.
字符串格式化,后面详细解释。
43.
将对象转化成string,valueOf 重载了很多方法,这边不再赘述。
44.
本质是从char数组中截取出部分字符,组成新的字符串。
45.
这个方法楼主一开始看的也是很懵,不知道有什么用,又来细线,可能是为了提高效率,从常量池取数据比从堆里面去数据要快一些。
PS:哪里不对可以在评论中指出,我都会一个个看的,觉得少东西也可以评论中提出来,我会做补充。
网友评论