In Kotlin, you usually don’t manually override toString(), equals(), and hashCode() if your class is just a value/data holder. Use a data class instead.
data class User(
val id: Int,
val name: String
)
Kotlin automatically generates:
toString()
equals()
hashCode()
copy()
componentN()
Example:
val a = User(1, "Alice")
val b = User(1, "Alice")
println(a) // User(id=1, name=Alice)
println(a == b) // true
println(a.hashCode() == b.hashCode()) // true
Manual override
If you need custom behavior, override them explicitly:
class User(
val id: Int,
val name: String
) {
override fun toString(): String {
return "User(id=$id, name=$name)"
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is User) return false
return id == other.id && name == other.name
}
override fun hashCode(): Int {
var result = id
result = 31 * result + name.hashCode()
return result
}
}
Important notes
Use == for equality in Kotlin:
a == b
This calls equals() internally.
Use === for reference equality:
a === b
This checks whether both variables point to the exact same object.
Custom equality example
Sometimes you only want equality based on one property, such as id:
class User(
val id: Int,
val name: String
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is User) return false
return id == other.id
}
override fun hashCode(): Int {
return id
}
override fun toString(): String {
return "User(id=$id, name=$name)"
}
}
The key rule is: if you override equals(), you should also override hashCode() consistently. Objects that are equal must have the same hash code.
