data class in Kotlin is a special type of class designed exclusively for storing data. The compiler automatically generates methods equals, hashCode, toString, copy and componentN based on the properties specified in the primary constructor. According to JetBrains documentation (2026), data class allows reducing boilerplate code by 50–70% compared to Java equivalents and is the foundation for value objects in Kotlin projects.
Key Takeaways
data class is a syntactic construct of Kotlin that automatically generates standard methods for classes whose main purpose is storing data. When declaring a data class, the compiler creates implementations of equals, hashCode, toString, copy and componentN based on all properties from the primary constructor.
Unlike regular classes in Java, where the developer has to manually write getters, setters, equals, hashCode and toString using IDE or libraries like Lombok, Kotlin provides a built-in mechanism. This not only reduces code but also guarantees consistency — automatic methods always correspond to the current property structure.
According to the JetBrains Kotlin Survey (2025), data class is used in 78% of Kotlin projects, making it one of the most sought-after language features. It is especially popular in architectures with DTOs, API response models and state objects in MVVM.
data class is declared with the data keyword before class. All properties involved in automatic methods are specified in the primary constructor.
data class User(
val id: Int,
val name: String,
val email: String
)
One line of code replaces dozens of lines of boilerplate in Java. The compiler generates equals, hashCode, toString, copy and component1–component3 for all three properties.
Automatic methods include only properties from the primary constructor. If a property is declared in the class body, it does not participate in equals, hashCode, toString and copy.
data class Product(
val id: Int,
val title: String
) {
var cachedPrice: Double = 0.0
// cachedPrice is NOT included in equals/hashCode/copy
}
Primary constructor of a data class must contain at least one parameter. All parameters must be marked val or var. You cannot use open, abstract, sealed or inner modifiers for a data class.
equals and hashCode are generated based on the values of all properties from the primary constructor. Two instances of a data class are considered equal if all their corresponding properties are equal.
In Java, object comparison by default is reference comparison (==). Value comparison requires overriding equals. Kotlin data class does this automatically, allowing you to use == for structural comparison.
data class Address(
val city: String,
val street: String
)
val a1 = Address("Moscow", "Tverskaya")
val a2 = Address("Moscow", "Tverskaya")
println(a1 == a2) // true
Method toString returns a readable representation of the object with names and values of all properties. This significantly simplifies logging and debugging compared to Java, where the default output shows the hash code in hexadecimal format.
According to Kotlin Documentation (2026), toString of a data class has the format: “User(id=1, name=John, email=john@example.com)”. When removing properties from the primary constructor, toString is automatically updated — the risk of desynchronization is eliminated.
copy is one of the key features of data class. It creates a shallow copy of the object with the ability to change values of specified properties.
data class Order(
val id: Long,
val status: String,
val amount: Double
)
val order = Order(1L, "Pending", 299.99)
val updatedOrder = order.copy(status = "Confirmed")
// updatedOrder.id = 1L, amount = 299.99, status = "Confirmed"
copy is indispensable in functional style and architectures with immutability. Instead of mutating an existing object, a new copy is created with modified fields, making the code more predictable and safe in multithreaded scenarios.
data class automatically generates functions component1, component2 and so on for each property in the order they are declared. This allows destructuring the object into variables.
val user = User(1, "Alice", "alice@example.com")
val (id, name, email) = user
println("$id: $name ($email)") // "1: Alice (alice@example.com)"
Destructuring also works in lambdas and for-each loops, making data class convenient for working with collections.
First limitation — data class does not support inheritance from another data class. You can only inherit from regular classes or interfaces.
Second — automatic methods include only primary constructor properties. Properties in the class body are ignored, which can lead to incorrect equals if you forget about this.
Third — data class cannot be open, abstract, sealed or inner. It is always final.
Fourth — for collections inside a data class, copy performs shallow copying. Changing elements inside the copied collection will affect the original.
According to Kotlin Best Practices (2026), data class is optimal for DTOs, API models, value objects and state objects. For components with business logic, it is recommended to use regular classes.
Frequently Asked Questions
No, a data class cannot inherit another data class. However, it can inherit a regular class or implement interfaces.
At least one property. The maximum number is not limited, but componentN is generated for destructuring.
No, automatic methods only consider properties from the primary constructor. Properties from the class body do not participate in equals, hashCode, toString and copy.
Yes, you can override equals, hashCode or toString in the data class body. In this case, the compiler does not generate its own implementation.
A data class automatically generates equals, hashCode, toString, copy and componentN. A regular class does not provide these methods without manual implementation.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also