收藏 | 万字长文彻底搞懂 String(一)

简介: 哈喽,大家好,我是指北君。java.lang.String 类可能是大家日常用的最多的类,但是对于它是怎么实现的,你真的明白吗?不知道不要紧,善解人意的指北君写下了这篇文章,包你一看就明白了。


1、String 类的定义


60.png

和上一篇博客所讲的 Integer 类一样,这也是一个用 final 声明的常量类,不能被任何类所继承,而且一旦一个String对象被创建, 包含在这个对象中的字符序列是不可改变的, 包括该类后续的所有方法都是不能修改该对象的,直至该对象被销毁,这是我们需要特别注意的(该类的一些方法看似改变了字符串,其实内部都是创建一个新的字符串,下面讲解方法时会介绍)。接着实现了 Serializable接口,这是一个序列化标志接口,还实现了 Comparable 接口,用于比较两个字符串的大小(按顺序比较单个字符的ASCII码),后面会有具体方法实现;最后实现了 CharSequence 接口,表示是一个有序字符的集合,相应的方法后面也会介绍。


2、字段属性


61.png


一个 String 字符串实际上是一个 char 数组。


3、构造方法


String 类的构造方法很多。可以通过初始化一个字符串,或者字符数组,或者字节数组等等来创建一个 String 对象。

 62.jpg63.png


4、equals(Object anObject) 方法


64.png

String 类重写了 equals 方法,比较的是组成字符串的每一个字符是否相同,如果都相同则返回true,否则返回false。


5、hashCode() 方法



65.png

String 类的 hashCode 算法很简单,主要就是中间的 for 循环,计算公式如下:

s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

s 数组即源码中的 val 数组,也就是构成字符串的字符数组。这里有个数字 31 ,为什么选择31作为乘积因子,而且没有用一个常量来声明?主要原因有两个:

①、31是一个不大不小的质数,是作为 hashCode 乘子的优选质数之一。

②、31可以被 JVM 优化,31 * i = (i << 5) - i。因为移位运算比乘法运行更快更省性能。


6、charAt(int index) 方法



66.png

我们知道一个字符串是由一个字符数组组成,这个方法是通过传入的索引(数组下标),返回指定索引的单个字符。


7、compareTo(String anotherString) 和 compareToIgnoreCase(String str) 方法


我们先看看 compareTo 方法:


67.png


源码也很好理解,该方法是按字母顺序比较两个字符串,是基于字符串中每个字符的 Unicode 值。当两个字符串某个位置的字符不同时,返回的是这一位置的字符 Unicode 值之差,当两个字符串都相同时,返回两个字符串长度之差。

compareToIgnoreCase() 方法在 compareTo 方法的基础上忽略大小写,我们知道大写字母是比小写字母的Unicode值小32的,底层实现是先都转换成大写比较,然后都转换成小写进行比较。


8、concat(String str) 方法


该方法是将指定的字符串连接到此字符串的末尾。68.png


首先判断要拼接的字符串长度是否为0,如果为0,则直接返回原字符串。如果不为0,则通过 Arrays 工具类(后面会详细介绍这个工具类)的copyOf方法创建一个新的字符数组,长度为原字符串和要拼接的字符串之和,前面填充原字符串,后面为空。接着在通过 getChars 方法将要拼接的字符串放入新字符串后面为空的位置。

注意:返回值是 new String(buf, true),也就是重新通过 new 关键字创建了一个新的字符串,原字符串是不变的。这也是前面我们说的一旦一个String对象被创建, 包含在这个对象中的字符序列是不可改变的。

相关文章
|
3月前
|
Java
【Java基础面试三十一】、String a = “abc“; ,说一下这个过程会创建什么,放在哪里?
这篇文章解释了在Java中声明`String a = "abc";`时,JVM会检查常量池中是否存在"abc"字符串,若不存在则存入常量池,然后引用常量池中的"abc"给变量a。
|
6月前
|
C++
C++初阶(十二)string的模拟实现
C++初阶(十二)string的模拟实现
39 0
|
1月前
|
存储 编译器 程序员
深度剖析C++string(上篇)(2)
深度剖析C++string(上篇)(2)
35 0
|
1月前
|
存储 Linux C语言
深度剖析C++string(上篇)(1)
深度剖析C++string(上篇)(1)
31 0
|
存储 Java 编译器
JDK8中String的intern()方法详细解读【内存图解+多种例子+1.1w字长文】
JDK8中String的intern()方法详细解读【内存图解+多种例子+1.1w字长文】
JDK8中String的intern()方法详细解读【内存图解+多种例子+1.1w字长文】
|
编译器 C语言 C++
【C++】一文带你吃透string的模拟实现 (万字详解)(下)
【C++】一文带你吃透string的模拟实现 (万字详解)(下)
【C++】一文带你吃透string的模拟实现 (万字详解)(下)
|
存储 编译器 C++
【C++】一文带你吃透string的模拟实现 (万字详解)(上)
【C++】一文带你吃透string的模拟实现 (万字详解)(上)
112 0
【C++】一文带你吃透string的模拟实现 (万字详解)(上)
|
Rust 算法 Python
【密码学】杂谈-字节数组和int之间的转换
本文还是来随便聊一聊,我们在去看一些密码学算法的结构的过程当中,我们经常的会发现,这些结构内部的数据的处理方式并不都是根据字节来处理的,有可能他们对于数据的处理用的u32或者说是u64,之前我们说了,在计算机的内部,最小的单位是字节,那么我们怎么将这个字节处理成为结构当中需要的u32或者u64呢?本文接下来就来聊一下他们之间的转换过程(还是老样子,只考虑无符号数)
【密码学】杂谈-字节数组和int之间的转换
|
安全 编译器 C语言
萌新不看会后悔的C++string字符串常用知识点总结
萌新不看会后悔的C++string字符串常用知识点总结
萌新不看会后悔的C++string字符串常用知识点总结