skip to content

data class & Generated Members

data class generates equals, hashCode, and toString from the primary-constructor properties. The follow-up interviewers reach for is what happens to properties declared in the body: they are excluded, which quietly breaks equality expectations.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

What members does the Kotlin compiler auto-generate when you mark a class as a `data class`, and what drives their content?

level: juniorimportance: must knowfreq 85%

answer

  1. equals + hashCode + toString
  2. Driven by primary-constructor properties only
  3. Body properties are excluded
  4. Structural (==) not reference (===)
  5. Replaces value-object boilerplate

basics

~10 s

Marking a class data makes the compiler write equals(), hashCode(), and toString() for you, based on the properties declared in the primary constructor, so you don't write that boilerplate by hand.

solid answer

~30 s

The `data` modifier instructs the compiler to generate `equals()`/`hashCode()` (structural equality and a matching hash), `toString()` (a readable form like `User(name=Ann, age=30)`), plus `componentN()` and `copy()`. The generated `equals`, `hashCode`, and `toString` are derived solely from properties declared in the primary constructor. Properties declared in the class body are excluded. The class must have at least one primary-constructor parameter, and those parameters must be `val`/`var`. This replaces the manual boilerplate you'd otherwise write to make value-like objects compare and print by content rather than by identity.

code

kotlin · 7 lines
kotlin
data class Point(val x: Int, val y: Int)

val p1 = Point(1, 2)
val p2 = Point(1, 2)
println(p1 == p2)        // true (structural equals)
println(p1.hashCode() == p2.hashCode()) // true
println(p1)             // Point(x=1, y=2)

go deeper

for a junior

Names the three generated members and that they come from constructor properties.

for a middle

Adds that body properties are excluded and that == maps to the generated equals.

for a senior

Explains the contract (hashCode consistent with equals) and the default identity behavior it replaces.

for a principal

Frames data classes as a value-semantics tool and discusses when value semantics are/aren't appropriate for a domain type.

## What a `data class` is A `data class` is a class declared with the `data` modifier. Its purpose is to hold data, so the compiler generates the boilerplate that value-like objects need. ## The generated members (this leaf focuses on three) For a `data class`, the compiler generates: - **`equals(other: Any?): Boolean`** — *structural* equality: two instances are equal when all primary-constructor properties are equal. This is what `==` calls in Kotlin. - **`hashCode(): Int`** — a hash combining the same properties, consistent with `equals` (equal objects produce equal hashes). - **`toString(): String`** — a readable representation, e.g. `User(name=Ann, age=30)`. (It also generates `componentN()` and `copy()`, but those are separate leaves.) ## What drives the content: the primary constructor Only properties declared **in the primary constructor** are used. A property declared in the class body is NOT part of `equals`/`hashCode`/`toString`. ```kotlin data class User(val name: String, val age: Int) { var lastLogin: Long = 0 // body property: ignored by equals/hashCode/toString } val a = User("Ann", 30).apply { lastLogin = 100 } val b = User("Ann", 30).apply { lastLogin = 999 } println(a == b) // true -> lastLogin not considered println(a) // User(name=Ann, age=30) -> lastLogin not shown ``` ## Why it matters Without `data`, a normal class uses the default `Any.equals` (reference identity, `===`) and `Any.toString` (class name + hash). So two different `User("Ann", 30)` objects would be unequal and print as `User@1b6d3586`. `data` flips this to content-based behavior. ## Requirements - The primary constructor needs **at least one** parameter. - All primary-constructor parameters must be marked `val` or `var`.

  • If you add a property in the class body, is it included in equals()?
    No. Only primary-constructor properties are used; body properties are ignored by the generated equals/hashCode/toString.
  • Does a plain (non-data) class compare two equal-looking instances as equal?
    No. It falls back to Any.equals, which is reference identity, so two distinct instances are unequal even with identical fields.

Like a name tag printed from a form: only the fields you filled on the form (the constructor) appear on the tag.

saying these in an interview costs you the question

  • Says data classes generate getters/setters as the 'main' feature (that's true of any val/var, not the data point)
  • Claims body properties are part of equals/hashCode
  • Confuses == (structural, equals) with === (referential identity)
  • Thinks data class auto-generates equals from ALL properties including body ones

context

open as a page

Why are properties declared in a data class body (rather than the primary constructor) excluded from generated `equals`/`hashCode`/`toString`, and what surprising bug can this cause?

level: middleimportance: should knowfreq 65%

basics

~20 s

The compiler only looks at the primary-constructor properties when writing equals, hashCode, and toString. A field added in the body is ignored, so two objects differing only by that field count as equal — which can silently lose data in sets or maps.

open as a page

What risks does the auto-generated `toString()` of a data class introduce in production logging, and how do you mitigate them?

level: middleimportance: should knowfreq 45%

basics

~10 s

The generated toString prints every constructor property, including secrets like passwords or tokens. If you log a data object, those values can leak into logs. You should override toString to mask sensitive fields.

open as a page

Explain how a data class's generated `equals` and `hashCode` satisfy the equals/hashCode contract, and what happens if a primary-constructor property is an array.

level: seniorimportance: should knowfreq 50%

basics

~20 s

The generated equals and hashCode use the same set of constructor properties, so equal objects always produce equal hashes — that's the contract. But arrays are compared by reference, so two data objects holding equal-content arrays can wrongly come out unequal.

open as a page

If a data class extends a superclass that defines `toString()`/`equals()`, or you write your own `toString()` in the data class, which one wins — the generated or the explicit one? How does inheritance interact with the generated members?

level: seniorimportance: nice to knowfreq 35%

basics

~10 s

If you write your own equals, hashCode, or toString inside the data class, the compiler uses yours instead of generating that one. The compiler only fills in the members you didn't provide.

open as a page