在 Kotlin 中,==
和 ===
是两种不同的比较操作符,分别对应 结构相等性检查 和 引用相等性检查。以下是它们的核心区别和使用场景:
1. ==
(结构相等)
-
作用 :检查两个对象的 内容是否相等 (等价于 Java 的
.equals()
)。 -
规则:
- 对于基本类型(如
Int
,Double
等),直接比较值是否相等。 - 对于对象类型(如自定义类),默认调用其
equals()
方法判断是否相等。 - 对于可空类型(如
String?
),会安全处理null
值:
null == null
返回true
,null == 非null对象
返回false
。
- 对于基本类型(如
-
示例:
inival a = 100 val b = 100 println(a == b) // true(基本类型比较值) val str1 = "Kotlin" val str2 = "Kotlin" println(str1 == str2) // true(String 内容相同) data class User(val name: String) val user1 = User("Alice") val user2 = User("Alice") println(user1 == user2) // true(数据类自动生成 equals(),比较属性值)
2. ===
(引用相等)
-
作用 :检查两个变量是否 指向同一个内存地址(即是否是同一个对象的引用)。
-
规则:
- 对于基本类型(如
Int
),若值相同且未装箱,可能返回true
(由 JVM 优化决定)。 - 对于对象类型,只有当两个引用指向同一实例时返回
true
。 - 对于字符串字面量,可能因字符串驻留(String Interning)优化导致
===
返回true
。
- 对于基本类型(如
-
示例:
inival a = 1000 val b = 1000 println(a === b) // true(JVM 缓存小整数,同一对象) val str1 = "Kotlin" val str2 = "Kotlin" println(str1 === str2) // true(字符串驻留优化,指向同一对象) val str3 = String("Kotlin".toCharArray()) println(str1 === str3) // false(不同实例) class User(val name: String) val user1 = User("Alice") val user2 = User("Alice") val user3 = user1 println(user1 === user2) // false(不同实例) println(user1 === user3) // true(同一实例)
3. 关键区别
操作符 | 比较内容 | 适用场景 | 对基本类型的影响 |
---|---|---|---|
== |
值或对象的内容 | 需要逻辑相等的场景(如数据类) | 直接比较值 |
=== |
内存地址(引用同一性) | 需确认是否为同一对象的场景 | 可能因装箱产生不同结果(见下表) |
4. 特殊场景
(1) 基本类型的装箱问题
Kotlin 对 Int
等基本类型进行自动装箱,但 JVM 会对小范围值(通常是 -128
到 127
)缓存对象,导致 ===
的行为不一致:
ini
val a: Int = 100 // 未装箱(基本类型)
val b: Int = 100
println(a === b) // true(JVM 缓存,同一对象)
val c: Int = 1000 // 超出缓存范围,自动装箱
val d: Int = 1000
println(c === d) // false(不同对象)
**(2) 数据类(Data Class)的 ==
**
数据类自动生成 equals()
,比较所有属性值:
ini
data class User(val name: String, val age: Int)
val user1 = User("Alice", 30)
val user2 = User("Alice", 30)
println(user1 == user2) // true(属性相同)
println(user1 === user2) // false(不同实例)
**(3) 普通类的 ==
**
普通类的 ==
默认等价于 ===
(比较引用),除非重写 equals()
:
ini
class User(val name: String)
val user1 = User("Alice")
val user2 = User("Alice")
println(user1 == user2) // false(未重写 equals())
5. 总结:何时使用哪种操作符?
-
**
==
(结构相等)** :- 检查对象内容是否相同(如数据类、字符串内容比较)。
- 处理业务逻辑中的等价性判断(如用户登录名是否匹配)。
-
**
===
(引用相等)** :- 确认是否为同一实例(如单例模式、对象复用优化)。
- 调试时检查对象是否被意外复制或修改。
- 慎用于基本类型(因自动装箱可能导致预期外的结果)。
6. 示例对比
ini
// 示例 1:基本类型
val num1 = 100
val num2 = 100
println(num1 == num2) // true
println(num1 === num2) // true(JVM 缓存)
val num3 = 1000
val num4 = 1000
println(num3 == num4) // true
println(num3 === num4) // false(超出缓存范围,不同对象)
// 示例 2:字符串
val s1 = "Kotlin"
val s2 = "Kotlin"
val s3 = String(s1.toCharArray())
println(s1 == s2) // true
println(s1 === s2) // true(字符串驻留)
println(s1 === s3) // false(不同实例)
// 示例 3:数据类 vs 普通类
data class DataUser(val id: Int)
class RegularUser(val id: Int)
val dataUser1 = DataUser(1)
val dataUser2 = DataUser(1)
println(dataUser1 == dataUser2) // true(属性相同)
println(dataUser1 === dataUser2) // false
val regularUser1 = RegularUser(1)
val regularUser2 = RegularUser(1)
println(regularUser1 == regularUser2) // false(引用不同)
println(regularUser1 === regularUser2) // false
通过合理选择 ==
和 ===
,可以确保代码在逻辑正确性和性能之间取得平衡。多数情况下优先使用 ==
,仅在需要严格判断对象同一性时使用 ===