跳至主要內容
深入解读String类的源码

4.4 字符串源码解读

我正坐在沙发上津津有味地读刘欣大佬的《码农翻身》——Java 帝国这一章,门铃响了。起身打开门一看,是三妹,她从学校回来了。

“三妹,你回来的真及时,今天我们打算讲 Java 中的字符串呢。”等三妹换鞋的时候我说。

“哦,可以呀,哥。听说字符串的细节特别多,什么字符串常量池了、字符串不可变性了、字符串拼接了、字符串长度限制了等等,你最好慢慢讲,否则我可能一时半会消化不了。”三妹的态度显得很诚恳。


沉默王二大约 18 分钟Java核心数组&字符串
掌握 Java二维数组:从基本概念到实际应用

4.2 二维数组

“二哥,今天我们简单过一下二维数组吧,挺简单的。”三妹放下手机对我说。

“好啊,本来不打算讲了,因为开发中用的其实不多,也很简单,就从一维到二维,也没啥可讲的,就简单聊聊吧。”我掐灭了手中的华子,长呼一口烟,飘过三妹的头顶,引起一阵轻微的咳嗽声(😂)

01、什么是二维数组

二维数组是一种数据类型,可以存储多行和多列的数据。它由一系列的行和列组成,每个元素都可以通过一个行索引和列索引来访问。例如,一个3行4列的二维数组可以表示为以下形式:

array = [
  [a, b, c, d],
  [e, f, g, h],
  [i, j, k, l]
]

沉默王二大约 6 分钟Java核心数组&字符串
掌握Java数组:一个非常特殊的对象

4.1 数组

“二哥,我看你公众号的一篇文章里提到,ArrayList 的内部是用数组实现的,我就对数组非常感兴趣,想深入地了解一下,今天终于到这个环节了,好期待呀!”三妹的语气里显得很兴奋。

“的确是的,看 ArrayList 的源码就一清二楚了。”我一边说,一边打开 Intellij IDEA,并找到了 ArrayList 的源码。

/**
 * The array buffer into which the elements of the ArrayList are stored.
 * The capacity of the ArrayList is the length of this array buffer. Any
 * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
 * will be expanded to DEFAULT_CAPACITY when the first element is added.
 */
transient Object[] elementData; // non-private to simplify nested class access

/**
 * The size of the ArrayList (the number of elements it contains).
 *
 * @serial
 */
private int size;

沉默王二大约 11 分钟Java核心数组&字符串
为什么Java字符串是不可变的?

4.5 字符串为什么不可变

String 可能是 Java 中使用频率最高的引用类型了,因此 String 类的设计者可以说是用心良苦。

比如说 String 的不可变性。

  • String 类被 final 关键字修饰,所以它不会有子类,这就意味着没有子类可以重写它的方法,改变它的行为。
  • String 类的数据存储在 char[] 数组中,而这个数组也被 final 关键字修饰了,这就表示 String 对象是没法被修改的,只要初始化一次,值就确定了。

沉默王二大约 6 分钟Java核心数组&字符串
字符串相等判断:Java中的equals()与==的区别与用法

4.9 如何判断字符串相等

“二哥,如何比较两个字符串相等啊?”三妹问。

“这个问题看似简单,却在 Stack Overflow 上有超过 370 万+的访问量。”我说,“这个问题也可以引申为 .equals() 和 ‘==’ 操作符有什么区别。”

  • “==”操作符用于比较两个对象的地址是否相等。
  • .equals() 方法用于比较两个对象的内容是否相等。

“不是很理解。”三妹感到很困惑。

“我来举个不恰当又很恰当的例子,一看你就明白了,三妹。”


沉默王二大约 9 分钟Java核心数组&字符串
最优雅的Java字符串String拼接是哪种方式?

4.10 如何拼接字符串

“哥,你让我看的《Java 开发手册》上有这么一段内容:循环体内,拼接字符串最好使用 StringBuilder 的 append() 方法,而不是 + 号操作符。这是为什么呀?”三妹疑惑地问。

“其实这个问题,我们之前在 StringBuilder 时已经聊过了。”我慢吞吞地回答道,“不过,三妹,哥今天来给你深入地讲讲。”


沉默王二大约 10 分钟Java核心数组&字符串
如何在Java中拆分字符串:详解String类的split()方法

4.11 如何拆分字符串

“哥,我感觉字符串拆分没什么可讲的呀,直接上 String 类的 split() 方法不就可以了!”三妹毫不客气地说。

“假如你真的这么觉得,那可要注意了,事情远没这么简单。”我微笑着说。

假如现在有这样一串字符序列“沉默王二,一枚有趣的程序员”,需要按照中文逗号“,”进行拆分,这意味着第一串字符序列为逗号前面的“沉默王二”,第二串字符序列为逗号后面的“一枚有趣的程序员”。

“这不等于没说吗?哥!”还没等我说,三妹就打断了我。

“别着急嘛,等哥说完。”我依然保持着微笑继续说,“在拆分之前,要先进行检查,判断一下这串字符是否包含逗号,否则应该抛出异常。”


沉默王二大约 7 分钟Java核心数组&字符串
如何优雅地打印Java数组?

4.3 打印数组

“哥,之前听你说,数组也是一个对象,但 Java 中并未明确的定义这样一个类。”看来三妹有在用心地学习。

“是的,因此数组也就没有机会覆盖 Object.toString() 方法。如果尝试直接打印数组的话,输出的结果并不是我们预期的结果。”我接着三妹的话继续说。

“那怎么打印数组呢?”三妹心有灵犀地把今天的核心问题提了出来。


沉默王二大约 5 分钟Java核心数组&字符串
深入理解Java字符串常量池

4.6 字符串常量池

“三妹,今天我们来学习一下字符串常量池,这是字符串中非常关键的一个知识点。”我话音未落,青岛路小学那边传来了嘹亮的歌声就钻进了我的耳朵,“唱 ~ 山 ~ 歌 ~”,我都有点情不自禁地哼唱起来了。

三妹赶紧拦住我说,“好了,开始吧,哥。”

new String("二哥")创建了几个对象

“先从这道面试题开始吧!”

String s = new String("二哥");

沉默王二大约 8 分钟Java核心数组&字符串
2