Kotlin Data Classes

Data classes

A data class is a class for storing data. A data class is declared by adding data before the class keyword. When a class is declared as a data class, Kotlin automatically generates the toString(), hashCode(), equals(), and copy() functions, and it is used almost like a regular class.

class Foo1(var name: String)        // Regular class
data class Foo2(var name: String)   // Data class

fun main() {
    var a1 = Foo1("devkuma")
    println(a1)              // Foo1@2280cdac

    var a2 = Foo2("devkuma")
    println(a2)              // Foo2(name=devkuma)

    var a3 = a2.copy()
    println(a3)              // Foo2(name=devkuma)
}

Characteristics of data classes

  • They cannot be inherited.
  • Constructor properties must be declared with val or var.
  • The constructor must declare at least one property.
  • abstract, open, sealed, and inner cannot be added.
  • If toString(), hashCode(), equals(), or copy() is overridden, the implemented function is used.

Automatically generated functions

The examples below use a regular class and a data class defined as follows.

Regular class:

class PersonGeneral(var name: String, val age: Int)

Data class:

data class PersonData(var name: String, val age: Int)

toString()

The toString() function returns the values of the properties defined in the constructor.

fun main() {
    var personGeneral = PersonGeneral("devkuma", 21)
    var personData = PersonData("devkuma", 21)

    println(personGeneral)
    println(personData)
}

Output:

basic.clazz.data.PersonGeneral@548c4f57
PersonData(name=devkuma, age=21)
  • The regular class toString() returned object information.
  • The data class toString() returns the properties and their values.

hashCode()

The hashCode() function returns different values for regular class objects, but returns the same value for data class objects with the same data.

The example below creates two regular class instances and two data class instances, then checks their hashCode() values.

fun main() {
    var personGeneral1 = PersonGeneral("devkuma", 21)
    var personGeneral2 = PersonGeneral("devkuma", 21)
    
    var personData1 = PersonData("devkuma", 21)
    var personData2 = PersonData("devkuma", 21)

    println(personGeneral1.hashCode())
    println(personGeneral2.hashCode())

    println(personData1.hashCode())
    println(personData2.hashCode())
}

Output:

1418481495
303563356
1111582818
1111582818
  • personGeneral1.hashCode() and personGeneral2.hashCode() returned different values.
  • personData1.hashCode() and personData2.hashCode() returned the same value.

equals()

Before looking at equals(), first compare Kotlin comparison operators with Java. Java and Kotlin differ in how they compare values and object identity in memory.

Check target Java Kotlin
Check whether values are equal .equals() == OR .equals()
Check whether they are the same object in memory == ===

The example below compares two data class instances that contain the same values.

fun main() {
    var personData1 = PersonData("devkuma", 21)
    var personData2 = PersonData("devkuma", 21)
    
    println(personData1 == personData2)
    println(personData1 === personData2)
}

Output:

true
false
  • Using == checks whether the values are the same, so true is returned.
  • Using === checks whether they are the same object in memory, so false is returned.

copy()

The copy() function can copy values while changing only properties defined in the constructor.

In the example below, one data class instance is created first, and then two more instances copy its property values with copy().

fun main() {
    val personData1 = PersonData("devkuma", 21)

    val personData2 = personData1.copy()
    val personData3 = personData1.copy(name = "kimkc")

    println(personData1)
    println(personData2)
    println(personData3)
}

Output:

PersonData(name=devkuma, age=21)
PersonData(name=devkuma, age=21)
PersonData(name=kimkc, age=21)
  • The first object copied the property values with the copy() function.
  • The second object copied the property values while changing only name with copy(name = "kimkc").

Destructuring declarations

Normally, to get variable values from an object, you would write code like this.

fun main() {
    val personData = PersonData("devkuma", 21)

    val name = personData.name
    val age = personData.age

    println("$name, $age years of age")
}

Output:

devkuma, 21 years of age

Kotlin supports destructuring declarations, so the same code can be written more briefly.

fun main() {
    val personData1 = PersonData("devkuma", 21)

    val (name, age) = personData1

    println("$name, $age years of age")
}

Output:

devkuma, 21 years of age
  • As in val (name, age) = personData1, each value of the data class is assigned to a variable.

References