Как создать переменную в дата классе Kotlin, которая не участвует в hashCode и equals
Что проверяют
Знаете ли вы, откуда data-класс берёт свойства для сгенерированных методов. Вопрос с подвохом: многие уверенно отвечают про @Transient, и интервьюер ждёт именно эту ошибку. Следом обычно спрашивают, что станет с таким полем при copy().
Как отвечать
Компилятор строит equals(), hashCode(), toString(), copy() и componentN() только по свойствам из первичного конструктора. Всё, что объявлено в теле класса, в этих методах не участвует:
data class User(val id: Int, val name: String) {
var lastSeen: Long = 0
}Два User с одинаковыми id и name будут равны при любом lastSeen.
Дальше назовите следствия:
copy(): поле из тела не копируется, у копии оно получает значение из инициализатора;toString(): в логах этого поля тоже не будет;- ручная реализация: если в теле data-класса явно написать
equals()иhashCode(), компилятор генерировать их не станет. Это второй способ, но тогда оба метода поддерживаете вы сами.
Про аннотации скажите прямо: @Transient из kotlin.jvm помечает поле для Java-сериализации, а @Transient из kotlinx.serialization исключает свойство из сериализации. На equals() и hashCode() ни одна из них не влияет. У Room есть @Ignore, и он тоже только про таблицу.
Где спотыкаются
Отвечают @Transient. Это прямая ошибка, и интервьюер часто просит тут же написать пример, где два таких объекта окажутся не равны.
Забывают про StateFlow. Он не пропускает новое значение, если оно равно текущему по equals(), поэтому UI-состояние, в котором изменилось только поле из тела класса, до экрана не дойдёт. То же с DiffUtil и ListAdapter, если areContentsTheSame сравнивает через ==.
Кладут в hashCode() изменяемые данные, а потом держат объект в HashSet или ключом HashMap. После изменения объект лежит не в той корзине и перестаёт находиться. Вынос поля в тело класса снимает эту проблему, но только если вы понимаете, зачем его туда вынесли.