В чем разница между == и === в котлине
В чем разница между двумя операторами сравнения ==
а также ===
в Котлине?
class A {
var foo = 1
}
var a1 = A()
var a2 = A()
println(a1 == a2) // output false
println(a1 === a2) // output false
a1 = a2
println(a1 == a2) // output true
println(a1 === a2) // output true
4 ответа
В Котлине доступны два типа равенства. Это: Структурное равенство и ссылочное равенство.
class A {
var foo = 1
}
var a1 = A()
var a2 = A()
Вот a1
а также a2
два экземпляра класса A
,
println(a1 == a2)
Это печатает false
так как a1
а также a2
не являются структурно равными.
println(a1 === a2)
Это печатает false
так как a1
а также a2
не ссылаются на один и тот же объект.
Но, если вы выполните эту строку: a1 = a2
затем,
a1 и a2 будут структурно равны, а a1 ссылается на экземпляр a2. Вот почему,
println(a1 == a2)
println(a1 === a2)
обе эти строки возвращают истину.
Короче говоря, из документов:
В Котлине существует два типа равенства:
- Структурное равенство (проверка на
equals()
) =>==
- Ссылочное равенство (две ссылки указывают на один и тот же объект) =>
===
Подробный ответ:
Структурное равенство (==
)
Отрицательный аналог
==
является
!=
По соглашению такое выражение, как
a == b
переводится на:
a?.equals(b) ?: (b === null)
если
a
не является
null
, он называет
equals(Any?)
функция, иначе он проверяет, что
b
ссылочно равно
null
.
Чтобы обеспечить реализацию пользовательской проверки равенства, переопределите
equals(other: Any?): Boolean
функция. Функции с тем же именем и другими сигнатурами, например equals(other: Foo), не влияют на проверку равенства с операторами.
==
и
!=
.
Референтное равенство (===
)
Отрицательный аналог
===
является
!==
a === b
оценивает
true
если и только если
a
и
b
указать на тот же объект. Для значений, которые во время выполнения представлены как примитивные типы (например,
Int
),
===
проверка равенства эквивалентна
==
чек.
Объяснение кода
Предположим, что определение
A
как вы определили в своем вопросе.
Фрагмент 1
>>> var a1 = A()
>>> var a2 = A()
>>> a1 == a2 // a1 and a2 are different instances of A
false
>>> a1 == a1
true
>>> a2 == a2
true
>>> a1 === a2 // a1 and a2 have references to different objects
false
Для обычных занятий реализация
equals
унаследовано от
Any
, и просто сделайте объект равным самому себе.
Фрагмент 2
>>> var a1 = A()
>>> var a2 = A()
>>> a1 = a2
>>> a1 == a2
true
>>> a1 === a2
true
a1
и
a2
указывают на тот же объект, поэтому
a1 == a2
и
a1 === a2
верните истину.
Фрагмент 3
Давайте переопределим
equals(Any?)
из
A
следующим образом:
class A {
var foo = 1
override fun equals(other: Any?): Boolean {
if (other == null || other !is A)
return false
return foo == (other as A).foo
}
}
Теперь запустим следующее:
>>> var a1 = A()
>>> var a2 = A()
>>> a1 == a2
true
>>> a1 === a2
false
Заметить, что
a1
и
a2
структурно равны, даже если они ссылаются на разные объекты.
Структурное равенство означает, что контент должен быть одинаковым.
"checks for equals() or ==".
Ссылочное равенство означает, что оба экземпляра должны указывать на один и тот же указатель.
"two objects points to same reference or ==="
Вы можете переопределить equals() и сделать то, что показано ниже.
class Person(val p : String) {
override fun toString(): String = "Person(p$p)"
override fun equals(other: Any?): Boolean {
if(other == null || other !is Person) {
return false
}
return p == other.p
}
}
давайте проверим это.
var a = Person("abc")
var b = Person("abc")
Line 1 => println(a == b)
Line 2 => println(a === b)
Line1 печатает "true"
Line2 печатает «ложь»
a = b
Line1 печатает "true"
Line2 печатает "true"
Окончательно,
=== всегда проверяет равенство ссылок, тогда как == проверяет эквивалентное содержимое и основано на вашей реализации.
Операторы Kotlin == и === (свежий взгляд: 6 случаев)
В Kotlin, если a и b представляют две переменные, тогда println(a==b) проверяет, являются ли два значения структурно равными или нет. Но println(a===b) проверяет, имеют ли a и b одинаковую ссылку или нет. Следующие примеры прояснят это.
// Case 1 : a and b are both Int
// EqCase1.kt
fun main() {
var a = 5
var b = 7
println(a==b) // false
//println(a===b) // identity equality for Int is deprecated
a = b
println(a==b) // true
//println(a===b) // identity equality for Int is deprecated
}
// Case 2 : a and b are Double and Integer
// EqCase2.kt
fun main() {
var a = 5.0
var b = 7
//println(a==b) // operator '==' cannot be applied to 'Double' and 'Int'
//println(a===b) // operator '===' cannot be applied to 'Double' and 'Int'
//a = b // inferred type is Int but Double was expected
//println(a==b) // inferred type is Int but Double was expected
println(a===b) // identity equality for Int is deprecated
}
// case 3 : a and b are mathematically same but of different types (Double and Any(say Int))
// EqCase3.kt
fun Eq(a: Double,b: Any) = if (a == b) "(a == b) is true" else "(a == b) is false"
//fun Eq1(a: Double,b: Any) = if (a === b) "(a === b) is true" else "(a === b) is false"
fun main() {
println(Eq(5.0,5)) // (a == b) is false
//println(Eq1(5.0,5))
}
/* O/p
EqCase3.kt:5:34: warning: identity equality for arguments of types Double and Any can be unstable because of implicit boxing
fun Eq1(a: Double,b: Any) = if (a === b) "(a === b) is true" else "(a === b) is false"
*/
// Case 4 : a and b are both Booleans
// EqCase4.kt
fun main() {
var a = true
var b = false
println(a==b) // false
//println(a===b) // identity equality for arguments of Boolean is deprecated
a = b
println(a==b) // true
//println(a===b) // identity equality for arguments of Boolean is deprecated
}
// Case 5 : a and b are both Strings
// EqCase5.kt
fun main() {
var a = "Anil"
var b = "Vijay"
println(a==b) // false
println(a===b) // false
a = b
println(a==b) // true
println(a===b) // true
}
// Case 6 : a and b are both of type arrayOf
// EqCase6.kt
fun main() {
var a = arrayOf("A","B","C")
var b = arrayOf("a","b","c")
println(a==b) // false
println(a===b) // false
a = b
println(a==b) // true
println(a===b) // true
}