Equality by value asks whether two objects contain the same meaningful data, rather than whether two references point to the same object. In Kotlin, `==` is the normal value-equality operator: it calls `equals` and handles null safely. Use `===` only when object identity matters. section 4.3.1 section 9.2.1
Compare customers by their stored data
A plain class uses inherited equality, so two separately created customers are not equal even when their fields match. Override `equals` to compare `name` and `postalCode`: ```kotlin class Customer(val name: String, val postalCode: Int) { override fun equals(other: Any?): Boolean { if (other == null || other !is Customer) return false return name == other.name && postalCode == other.postalCode } } Customer("Alice", 342562) == Customer("Alice", 342562) // true ``` The nullable `Any?` parameter accepts any possible comparison target. The type check makes accessing `other`'s properties safe; equality then follows from both properties being equal. section 4.3.1
A manual `equals` implementation must be paired with a consistent `hashCode` implementation when instances are used in hash-based containers. Otherwise, an object equal by value may not be found in a `HashSet` or when used as a `HashMap` key. section 4.3.1
For a class whose main purpose is holding data, a data class removes this boilerplate. Kotlin generates `equals`, `hashCode`, and `toString`; generated equality includes every property declared in the primary constructor. Properties declared elsewhere do not participate in equality or hash-code calculation. section 4.3.2 section 4.3
Let a data class define value equality
```kotlin data class Customer(val name: String, val postalCode: Int) val first = Customer("Sam", 11521) val same = Customer("Sam", 11521) println(first == same) // true ``` The two instances are distinct objects, but their primary-constructor property values match. Their generated hash codes also match, making the class suitable for hash-based use while those values remain unchanged. section 4.3.2
`==` first accounts for null, then invokes `equals` for a non-null receiver; this is why nullable values can be compared directly. section 9.2.1
A hand-written `equals` can use `other === this` as a quick identity check before checking the type and fields. `!=` is the inverse equality test. Unlike Java, Kotlin reserves `===` for reference identity, avoiding the need to remember that `==` has different meanings for primitives and references. section 9.2.1 section 4.3.1
Prefer read-only (`val`) properties for data-class values used as map keys or set members. Changing state after insertion can leave a hash-based container in an invalid state; immutable instances are also easier to reason about in multithreaded code. section 4.3.2


