Depending on how MetricCategory.Async.toString()
is implemented the outcome of the operation might be arbitrary. Consider following example:
class MetricCategory {
object Async {
override fun toString(): String {
return "Async"
}
}
}
This implementation would result in true
, true
printed out. As documented the ===
operator compares referential equality:
evaluates to true if and only if a and b point to the same object.
But why are the 2 constant string expressions the same object? This is caused by a feature of JVM (and other runtimes) called string interning:
In computer science, string interning is a method of storing only one
copy of each distinct string value, which must be immutable. Interning
strings makes some string processing tasks more time- or
space-efficient at the cost of requiring more time when the string is
created or interned. The distinct values are stored in a string intern
pool.
String interning does not happen automatically in JVM but it can be triggered manually.
class MetricCategory {
object Async {
override fun toString(): String {
val result = "a".toUpperCase() + "SYNC".toLowerCase()
return result.intern()
}
}
}
The above example would print true
, true
again but only because we've called String.intern
.
Consider below examples:
println("Async" == "Async") // true, obviously
println("Async" === "Async") // true, string interning for literals
println("Async" == java.lang.String("Async").toString())// true, obviously
println("Async" === java.lang.String("Async").toString()) // false, new instance on the right
println("Async" === java.lang.String("Async").toString().intern()) // true, right changed to shared instance
Further reading: