Почему nullableValue === other печатает true для 1, но false для 1000?
Предскажите и объясните четыре строки вывода. Поле value имеет тип Int, поле nullableValue — Int?, а compareInt вызывается с 1, затем с 1000.
class IntHolder(private val value: Int) {
private val nullableValue: Int? = value
fun compareInt(other: Int) {
println(value === other)
println(nullableValue === other)
}
}
// IntHolder(1).compareInt(1)
// IntHolder(1000).compareInt(1000)
Определите причину вывода.
Вывод — true / true / true / false. value — примитив int, поэтому === сравнивает по значению; nullableValue — упакованный Integer, и === сравнивает ссылки. JVM кэширует Integer для -128..127: 1 берёт кэшированный экземпляр, 1000 упаковывается заново.
- ✗Думать, что
===сравнивает упакованныйIntegerпо значению, а не по ссылке - ✗Забывать, что кэш
Integerв JVM охватывает лишь-128..127 - ✗Считать, что
value(примитивint) иnullableValue(Int?) ведут себя одинаково
- →Какой оператор сравнит эти значения по содержимому независимо от кэша?
- →Зачем JVM вообще кэширует маленькие значения
Integer?
Баг (поведение)
value имеет тип Int → компилируется в примитив int. Оператор === для примитивов сравнивает значения, поэтому обе строки для value дают true.
nullableValue имеет тип Int? → компилируется в объект Integer. === для объектов сравнивает ссылки, а не значения.
class IntHolder(private val value: Int) {
private val nullableValue: Int? = value // упакован в Integer
fun compareInt(other: Int) {
println(value === other) // примитив: по значению
println(nullableValue === other) // Integer: по ссылке
}
}
JVM кэширует объекты Integer в диапазоне -128..127. Значение 1 попадает в кэш — other (тоже упакованный для === с объектом) и nullableValue ссылаются на один кэшированный объект → true. Значение 1000 вне кэша — создаются два разных объекта → false.
Итог: true / true / true / false.
Исправление
Для сравнения по содержимому используйте == (структурное равенство), а не ===:
println(nullableValue == other) // ✅ true для 1 и для 1000