Why does nullableValue === other print true for 1 but false for 1000?
Predict and explain the four printed lines. The value field is Int, the nullableValue field is Int?, and compareInt is called with 1 then 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)
Diagnose the cause of the output.
Output is true / true / true / false. value is a primitive int, so === compares by value; nullableValue is a boxed Integer, so === compares references. The JVM caches Integer for -128..127: 1 reuses a cached instance, 1000 boxes fresh.
- ✗Thinking
===compares values for boxedInteger, not references - ✗Forgetting the JVM
Integercache only spans-128..127 - ✗Assuming
value(a primitiveint) andnullableValue(Int?) behave identically
- →Which operator would compare these values by content regardless of caching?
- →Why does the JVM cache small
Integervalues in the first place?
The behaviour
value is Int → compiled to the primitive int. The === operator on primitives compares values, so both value lines print true.
nullableValue is Int? → compiled to an Integer object. === on objects compares references, not values.
class IntHolder(private val value: Int) {
private val nullableValue: Int? = value // boxed Integer
fun compareInt(other: Int) {
println(value === other) // primitive: by value
println(nullableValue === other) // Integer: by reference
}
}
The JVM caches Integer objects in the range -128..127. The value 1 is in the cache — other (boxed for the object ===) and nullableValue point at the same cached object → true. The value 1000 is outside the cache — two distinct objects are created → false.
Result: true / true / true / false.
The fix
To compare by content, use == (structural equality), not ===:
println(nullableValue == other) // ✅ true for both 1 and 1000