@@ -9,9 +9,10 @@ description: Java程序员进阶之路,小白的零基础Java教程,从入
9
9
head :
10
10
- - meta
11
11
- name : keywords
12
- content : Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,java字符串,String,equals
12
+ content : Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,java字符串,String,equals,java equals,java string 比较,java字符串比较
13
13
---
14
14
15
+ # 4.8 Java如何判断两个字符串是否相等?
15
16
16
17
“二哥,如何比较两个字符串相等啊?”三妹问。
17
18
@@ -53,11 +54,11 @@ public boolean equals(Object obj) {
53
54
54
55
但实际情况中,有不少类重写了 ` .equals() ` 方法,因为比较内存地址的要求比较严格,不太符合现实中所有的场景需求。拿 String 类来说,我们在比较字符串的时候,的确只想判断它们俩的内容是相等的就可以了,并不想比较它们俩是不是同一个对象。
55
56
56
- 况且,字符串有字符串常量池的概念 ,本身就推荐使用 ` String s = "字符串" ` 这种形式来创建字符串对象,而不是通过 new 关键字的方式,因为可以把字符串缓存在字符串常量池中,方便下次使用。
57
+ 况且,字符串有 [ 字符串常量池 ] ( https://tobebetterjavaer.com/string/constant-pool.html ) 的概念 ,本身就推荐使用 ` String s = "字符串" ` 这种形式来创建字符串对象,而不是通过 new 关键字的方式,因为可以把字符串缓存在字符串常量池中,方便下次使用,不用遇到 new 就在堆上开辟一块新的空间 。
57
58
58
59
“哦,我明白了。”三妹说。
59
60
60
- “那就来看一下 ` .equals() ` 方法的源码吧。”我说。
61
+ “那就来看一下 String 类的 ` .equals() ` 方法的源码吧。”我说。
61
62
62
63
``` java
63
64
public boolean equals(Object anObject) {
@@ -92,7 +93,39 @@ public static boolean equals(byte[] value, byte[] other) {
92
93
}
93
94
```
94
95
95
- 我的 JDK 版本是 Java 17,也就是最新的 LTS(长期支持)版本。该版本中,String 类使用字节数组实现的,所以比较两个字符串的内容是否相等时,可以先比较字节数组的长度是否相等,不相等就直接返回 false;否则就遍历两个字符串的字节数组,只有有一个字节不相等,就返回 false。
96
+ 这个 JDK 版本是 Java 17,也就是最新的 LTS(长期支持)版本。该版本中,String 类使用字节数组实现的,所以比较两个字符串的内容是否相等时,可以先比较字节数组的长度是否相等,不相等就直接返回 false;否则就遍历两个字符串的字节数组,只有有一个字节不相等,就返回 false。
97
+
98
+ 这是 Java 8 中的 equals 方法源码:
99
+
100
+ ``` java
101
+ public boolean equals(Object anObject) {
102
+ // 判断是否为同一对象
103
+ if (this == anObject) {
104
+ return true ;
105
+ }
106
+ // 判断对象是否为 String 类型
107
+ if (anObject instanceof String ) {
108
+ String anotherString = (String )anObject;
109
+ int n = value. length;
110
+ // 判断字符串长度是否相等
111
+ if (n == anotherString. value. length) {
112
+ char v1[] = value;
113
+ char v2[] = anotherString. value;
114
+ int i = 0 ;
115
+ // 判断每个字符是否相等
116
+ while (n-- != 0 ) {
117
+ if (v1[i] != v2[i])
118
+ return false ;
119
+ i++ ;
120
+ }
121
+ return true ;
122
+ }
123
+ }
124
+ return false ;
125
+ }
126
+ ```
127
+
128
+ JDK 8 比 JDK 17 更容易懂一些:首先判断两个对象是否为同一个对象,如果是,则返回 true。接着,判断对象是否为 String 类型,如果不是,则返回 false。如果对象为 String 类型,则比较两个字符串的长度是否相等,如果长度不相等,则返回 false。如果长度相等,则逐个比较每个字符是否相等,如果都相等,则返回 true,否则返回 false。
96
129
97
130
“嗯,二哥,这段源码不难理解。”三妹自信地说。
98
131
@@ -106,8 +139,7 @@ new String("小萝莉").equals("小萝莉")
106
139
107
140
“输出什么呢?”我问。
108
141
109
- “` .equals() ` 比较的是两个字符串对象的内容是否相等,所以结果为 true。”三妹答。
110
-
142
+ “` .equals() ` 比较的是两个字符串对象的内容是否相等,所以结果为 true。”三妹不假思索地答到。
111
143
112
144
113
145
第二题:
@@ -142,6 +174,8 @@ new String("小萝莉") == new String("小萝莉")
142
174
143
175
“由于‘小’和‘萝莉’都在字符串常量池,所以编译器在遇到‘+’操作符的时候将其自动优化为“小萝莉”,所以返回 true。”
144
176
177
+ PS:至于为什么,查看这篇[ String、StringBuilder、StringBuffer] ( https://tobebetterjavaer.com/string/builder-buffer.html )
178
+
145
179
第六题:
146
180
147
181
``` java
@@ -150,6 +184,8 @@ new String("小萝莉").intern() == "小萝莉"
150
184
151
185
“` new String("小萝莉") ` 在执行的时候,会先在字符串常量池中创建对象,然后再在堆中创建对象;执行 ` intern() ` 方法的时候发现字符串常量池中已经有了‘小萝莉’这个对象,所以就直接返回字符串常量池中的对象引用了,那再与字符串常量池中的‘小萝莉’比较,当然会返回 true 了。”三妹说。
152
186
187
+ PS:[ intern] ( https://tobebetterjavaer.com/string/intern.html ) 方法我们之前已经深究过了。
188
+
153
189
哇,不得不说,三妹前几节的字符串相关内容都完全学会了呀!
154
190
155
191
“三妹,哥再给你补充一点。”我说。
@@ -220,6 +256,45 @@ public boolean contentEquals(CharSequence cs) {
220
256
221
257
从源码上可以看得出,如果 cs 是 StringBuffer,该方法还会进行同步,非常的智能化;如果是 String 的话,其实调用的还是 ` equals() ` 方法。当然了,这也就意味着使用该方法进行比较的时候,多出来了很多步骤,性能上有些损失。
222
258
259
+ 同样来看一下 JDK 8 的源码:
260
+
261
+ ``` java
262
+ public boolean contentEquals(CharSequence cs) {
263
+ // argument can be any CharSequence implementation
264
+ if (cs. length() != value. length) {
265
+ return false ;
266
+ }
267
+ // Argument is a StringBuffer, StringBuilder or String
268
+ if (cs instanceof AbstractStringBuilder ) {
269
+ char v1[] = value;
270
+ char v2[] = ((AbstractStringBuilder )cs). getValue();
271
+ int i = 0 ;
272
+ int n = value. length;
273
+ while (n-- != 0 ) {
274
+ if (v1[i] != v2[i])
275
+ return false ;
276
+ i++ ;
277
+ }
278
+ return true ;
279
+ }
280
+ // Argument is a String
281
+ if (cs. equals(this ))
282
+ return true ;
283
+ // Argument is a non-String, non-AbstractStringBuilder CharSequence
284
+ char v1[] = value;
285
+ int i = 0 ;
286
+ int n = value. length;
287
+ while (n-- != 0 ) {
288
+ if (v1[i] != cs. charAt(i))
289
+ return false ;
290
+ i++ ;
291
+ }
292
+ return true ;
293
+ }
294
+ ```
295
+
296
+ 同样更容易理解一些:首先判断参数长度是否相等,不相等则返回 false。如果参数是 AbstractStringBuilder 的实例,则取出其 char 数组,遍历比较两个 char 数组的每个元素是否相等。如果参数是 String 的实例,则直接调用 equals 方法比较两个字符串是否相等。如果参数是其他实现了 CharSequence 接口的对象,则遍历比较两个对象的每个字符是否相等。
297
+
223
298
“是的,总体上感觉还是 ` Objects.equals() ` 比较舒服。”三妹的眼睛是雪亮的,发现了这个方法的优点。
224
299
225
300
---
0 commit comments