Метод равенства для класса данных в котлине
У меня есть следующий класс данных
data class PuzzleBoard(val board: IntArray) {
val dimension by lazy { Math.sqrt(board.size.toDouble()).toInt() }
}
Я прочитал, что классы данных в Kotlin получают бесплатный метод equals()/hashcode().
Я создал два объекта.
val board1 = PuzzleBoard(intArrayOf(1,2,3,4,5,6,7,8,0))
val board2 = PuzzleBoard(intArrayOf(1,2,3,4,5,6,7,8,0))
Но все же следующие утверждения возвращают false.
board1 == board2
board1.equals(board2)
Ответы
Ответ 1
В тестах проверки соответствия классов Kotlin data
, массивы, как и другие классы, сравниваются с помощью equals(...)
, который сравнивает ссылки массивов, а не контент. Это поведение описано здесь:
Итак, всякий раз, когда вы говорите
вы получаете массивы, сравниваемые по equals()
, то есть по ссылке.
Учитывая, что
val arr1 = intArrayOf(1, 2, 3)
val arr2 = intArrayOf(1, 2, 3)
println(arr1 == arr2) // false is expected here
println(PuzzleBoard(arr1) == PuzzleBoard(arr2)) // false too
Чтобы переопределить это и сопоставить структурные массивы, вы можете реализовать equals(...)
+ hashCode()
в своем классе данных, используя Arrays.equals(...)
и Arrays.hashCode(...)
:
override fun equals(other: Any?): Boolean{
if (this === other) return true
if (other?.javaClass != javaClass) return false
other as PuzzleBoard
if (!Arrays.equals(board, other.board)) return false
return true
}
override fun hashCode(): Int{
return Arrays.hashCode(board)
}
Этот код - это то, что IntelliJ IDEA может автоматически генерировать для не-данных классов.
Другим решением является использование List<Int>
вместо IntArray
. Списки сопоставляются структурно, поэтому вам не нужно переопределять что-либо.
Ответ 2
Для классы данных в методе Kotlin метод hashcode() будет генерировать и возвращать одно и то же целое число, если значения параметров одинаковы для обоих объектов.
val user = User("Alex", 1)
val secondUser = User("Alex", 1)
val thirdUser = User("Max", 2)
println(user.hashCode().equals(secondUser.hashCode()))
println(user.hashCode().equals(thirdUser.hashCode()))
Запуск этого кода вернет True и False, как если бы мы создали объект secondUser, мы передали тот же аргумент, что и объект пользователь, поэтому целое число hashCode(), сгенерированное для обоих из них, будет таким же.
также, если вы проверите это:
println(user.equals(thirdUser))
Он вернет false.
В соответствии с методом hashCode() docs
open fun hashCode(): Int (source)
Возвращает значение хэш-кода для объекта. Общий договор hashCode:
Всякий раз, когда он вызывается одним и тем же объектом более одного раза, hashCode метод должен последовательно возвращать одно и то же целое число, если нет информация, используемая при равных сравнениях с объектом, изменяется.
Если два объекта равны в соответствии с методом equals(), то вызов метод hashCode на каждом из двух объектов должен целочисленный результат.
Подробнее см. в этом обсуждении здесь
Ответ 3
Поздний ответ, но он может помочь кому-то, кто пришел к этому вопросу из поиска:
В Kotlin equals()
ведет себя по-разному между List
и Array
, как вы можете видеть из кода ниже:
val list1 = listOf(1, 2, 3)
val list2 = listOf(1, 2, 3)
val array1 = arrayOf(1, 2, 3)
val array2 = arrayOf(1, 2, 3)
//Side note: using a==b is the same as a.equals(b)
val areListsEqual = list1 == list2// true
val areArraysEqual = array1 == array2// false
List.equals()
проверяет, имеют ли два списка одинаковый размер и содержат ли они одинаковые элементы в одинаковом порядке.
Array.equals()
просто выполняет проверку ссылки на экземпляр. Поскольку мы создали два массива, они указывают на разные объекты в памяти, поэтому они не считаются равными.
Начиная с Kotlin 1.1, для достижения того же поведения, что и с List
, вы можете использовать Array.contentEquals()
.
Источник: Array.contentEquals() docs ;
List.equals() документы