Please help me understand this piece of code in the kotlin docs:-
val a: Int = 10000
print(a === a) // Prints 'true'
val boxedA: Int? = a
val anotherBoxedA: Int? = a
print(boxedA === anotherBoxedA) // !!!Prints 'false'!!!
Now, I understand that first int a = 10000
then in the next line it is comparing it using ===
.
Now the question is why when it assigned boxedA=a
, it checked if it is null using int?
. Can it just be written like this:-
val boxedA: Int=a
Please if I'm understanding it the wrong way, someone guide to check the right place or explain it a bit for me.
when it assigned boxedA = a
, it checked if it is null using int?
I have no idea what you mean by this. Making a variable have the type Int?
makes it a variable that can either store an Int
or null
. There is no checking happening at this assignment. If you have a non-null value to assign to the variable, just make it non-nullable, without the ?
in the type:
val copyOfA: Int = a
You can even omit the type, and get Int
inferred:
val copyOfA = a
As for the comparisons:
==
is used for comparing by value in Kotlin (this is the equivalent of using equals
in Java), ===
is used for comparing references (this is ==
in Java).
When you create boxedA
and anotherBoxedA
, you create two Integer
instances under the hood (because nullable variables can't be represented by primitives). These will be equal when compared with ==
(they have the same value), but not when compared with ===
(they are different instances).
You can see the relevant part of the offical docs here.
First, the Int
will be mapped to java int
/Integer
depending on its context. If Int
is a generic argument, then its mapped type is Integer
. Otherwise, it is a primitive type int
. for example:
val a:Int = 1
//final int a = 1; //mapped to java code
val numbers:List<Int> = asList(1,2,3)
//final List<Integer> numbers = asList(1, 2, 3); //mapped to java code
Secondly, boxing an Int
to an Int?
is same behavior as java boxing an int
to an Integer
, for example:
val a:Int = 1 // int a = 1;
val b:Int? = a; // Integer b = a;
Why the boxed Integers are not the same?
This is because Integer only caching values in the range [-128, 127]
. the the variable a
above is out of the cache range, it will create a new Integer instance for each boxing rather than using a cached value. for example:
// v--- 1 is in cache range
val ranged: Int = 1
val boxedRanged1: Int? = ranged
val boxedRanged2: Int? = ranged
println(boxedRanged1 === boxedRanged2) //true
// v--- 128 is out of cache range
val excluded: Int = 128
val boxedExcluded1: Int? = excluded
val boxedExcluded2: Int? = excluded
println(boxedExcluded1 === boxedExcluded2) //false
it checked if it is null using int?
That is not what it means.
Kotlin's null safety feature does not allow a variable to be set as null by default.
Check here.
val anotherBoxedA: Int? = a
This means that anotherBoxedA
can be assigned null or is nullable.
val anotherBoxedA: Int? = null
This will be allowed.