Я вижу, что пишу тест, в котором я не могу утверждать, что два запечатанных класса с одним и тем же «подклассом» и одинаковым значением под капотом равны. Они различны.
fun main() {
val a1 = MySealed.A("foo")
val a2 = MySealed.A("foo")
System.out.println(a1 == a2)
val a3 = MySealedWithEqualsAndHashCodeOverriden.A("foo")
val a4 = MySealedWithEqualsAndHashCodeOverriden.A("foo")
System.out.println(a3 == a4)
}
sealed class MySealed(val value: String) {
class A(value: String) : MySealed(value)
}
sealed class MySealedWithEqualsAndHashCodeOverriden(val value: String) {
class A(value: String) : MySealedWithEqualsAndHashCodeOverriden(value) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
return true
}
override fun hashCode(): Int {
return javaClass.hashCode()
}
}
}
Эта основная функция возвращает:
false
true
Я действительно не понимаю, почему такое поведение. Я думаю, это связано с природой закрытых классов, и я этого не понимаю?
заранее спасибо





Классы Kotlin Sealed не переопределяют equals() реализацию по умолчанию из Object класса Java. Это означает, что объекты сравниваются с использованием их ссылки, поэтому a1 и a2 не равны.
Классы данных Kotlin, в свою очередь, переопределяют метод equals() на основе всех свойств, объявленных в основном конструкторе (подробнее о них читайте в https://kotlinlang.org/docs/data-classes.html).
Это прекрасно. Но рассмотрите возможность использования классов данных, если они соответствуют вашему варианту использования;)
Это нормальное поведение для любого класса — два разных экземпляра по умолчанию не равны, потому что он проверяет ссылочное равенство (т. е. две ссылки указывают на один и тот же объект в памяти).
class NormalClass(val value: String)
val a = NormalClass("foo")
val b = NormalClass("foo")
println(a == b)
> false
data classes предоставляют реализацию equals и hashCode по умолчанию, которая игнорирует ссылочное равенство и просто сравнивает тип объекта и значения свойств в конструкторе.
data class DataClass(val value: String)
val a = DataClass("foo")
val b = DataClass("foo")
println(a == b)
> true
sealed class на самом деле просто специальный тип, которому может принадлежать класс, который в основном используется для таких вещей, как определение всех возможных объектов, которые имеют этот тип. Это позволяет вам группировать разрозненные классы и объекты вместе и выполнять такие действия, как исчерпывающее сопоставление с образцом (например, предложение when, работающее с объектом MySealed, может сказать, когда вы проверили все возможные члены этого типа)
Ваш класс A является обычным классом, поэтому два его экземпляра по умолчанию не равны. Если бы вы сделали это object в MySealed, это был бы только один экземпляр. В этом смысле он может работать как enum class. Закрытый класс позволяет смешивать и сочетать эти разные типы с некоторыми преимуществами и недостатками.
Вы можете просто создать A класс данных внутри запечатанного класса, если хотите, чтобы они совпадали, если у них одинаковые value, но также были MySealed
Спасибо за быстрый ответ. Итак, как вы думаете, имеет ли смысл переопределять метод запечатанного класса equals или это неприятный запах использования неправильного инструмента?