Reputation: 923
Actually, I am new to kotlin; therefore, this question may be very basic.
According to kotlin documentation, two variables can be compared with ===
and ==
operators.
First one ('==') checks if they have same content or not, and the second one ('+==') checks if they have same reference or not.
However, I cannot find any built-in class whose objects have same content, but with different references.
var str1 : String = "Hello World"
var str2 : String = "Hello World"
if( str1 == str2 ){ // yes
print("Their contents are same\n")
{
if( str1 === str2 ){ // yes
print("Their references are same\n")
}
Instances of all classes I have encountered up to now have same reference if their contents are same. How do we define two objects which have same content, but different references ?
Upvotes: 1
Views: 502
Reputation: 41598
Referential equality is checked by the
===
operation (and its negated counterpart!==
).a === b
evaluates to true if and only if a and b point to the same object.
In other words the ===
operator compares if a
and b
are the same reference. Using it on some basic types can be misleading because of:
An example would be:
val a:Int? = 123
val b:Int? = 123
println(a === b) // => true
val c:Int? = 130
val d:Int? = 130
println(c === d) // => false
Obviously in both cases the a == b
and c == d
is true.
Since string interning is also possible at compile time the ===
also returns true
in simple scenarios:
val a = "ala"
val b = "ala"
println(a === b) // => true
val c = "!ala".substring(1)
val d = "!ala".substring(1)
println(c === d) // => false
Structural equality is checked with the
==
operator (and its negated counterpart!=
). By convention, an expression likea == b
is translated to:
a?.equals(b) ?: (b === null)
As we saw above it is perfectly normal for built-in classes like String
and Int
to return false for reference equality ===
even though their contents are equal. Kotlin lets us define classes which can easily be checked for structural equality with data classes
like so:
data class Address(val city:String, val street1:String)
val a = Address("Warsaw", "Jagielońska")
val b = Address("Warsaw", "Jagielońska")
println(a === b) // => false
println(a == b) // => true
Upvotes: 3
Reputation: 5649
The === is not working because of the way you are defining the String. If you create a string using a literal, it will point to the same String in the String pool.
var str1 = "Hello World"
var str2 = "Hello World"
val str3 = buildString { "Hello World" }
val str4 = buildString { "Hello World" }
var result = str1===str2 // true
println(result)
result = str1 == str2 // true
println(result)
result = str3 === str4 // false
println(result)
result = str3 == str4 // true
println(result)
Upvotes: 2
Reputation: 89528
Comparing String
references like that will return true
, because the JVM optimizes your example code by reusing the first String
instance, since it's immutable anyway. See more discussion about this here, for example.
If you call the constructor of a class directly however, you'll skip any optimizations, and get different instances:
val i1 = Integer(1)
val i2 = Integer(1)
println(i1 == i2) // true
println(i1 === i2) // false
Sidenote: in Java, I'd have shown this example with new String("Hello world")
, but apparently the Kotlin String
class doesn't have a constructor of that form. Strange.
Upvotes: 2