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