In this section, we will learn what the data classes are and how to use them in Kotlin.
What is data class in Kotlin?
A data class is a type of class that its main purpose is to create objects that are used for storing data.
Essentially, they are here to present data and you usually don’t create a function for such type of class (Only properties).
Note that other than the purpose of a data class, there’s literally no difference between a data class and a normal class.
How to create a data class in Kotlin?
This is how we create a data class in Kotlin:
data class ClassName (parameters){ }
data
: we create a data class by putting the keyword data in front of the target class.
Also note that a data class must have a primary constructor. But the number of parameters we set here for this constructor is irrelevant and it’s related to the design of that data class.
Note that you can put any property or functions in the body of a data class, but we usually only put properties for a data class (and these properties are declared within the constructor itself using the val and var keywords)
Example: creating a data class in Kotlin
data class Person(var firstName:String, var lastName:String){} fun main(){ var person = Person("John","Doe") var secondPerson = Person("Jack","Bauer") }
Here we have a data class named Person, and it has two properties name firstName and lastName
Note: the way we create an object from a data class is no difference than creating an object from a normal class.
Kotlin Data Class and Equality
One of the differences between an object of type data class and a normal object (created from a typical non-data class) is that the comparison between two data classes using the ==
operator is based on the values of the properties of these objects!
Basically, if you compare two objects of type a data class using the == operator, the values of each property in the two objects will be checked and if they were equal (meaning both had the same values for their properties) then the result of the ==
will be true.
But applying the ==
operator on two objects of concrete non-data class type will result true only if both operands are pointing to the same memory location! Basically, you get the value true if there’s one object and both variables are pointing to that object!
Example: checking the equality of data class objects in Kotlin
data class Person(var firstName:String, var lastName:String){} fun main(){ var person = Person("John","Doe") var secondPerson = Person("Jack","Bauer") var thirdPerson = Person("John","Doe") println(person == secondPerson) println(person == thirdPerson) println(secondPerson == thirdPerson) }
Output:
false true false
As you can see, the person
and thirdPerson
objects have the same values for their properties and so the result of calling the ==
operator on these two objects results true.
Note: the data type of the objects still must be the same! For example, here both objects are of the same type! Otherwise, if data types are different and we run the == operator on the objects, we will get an error instead of a boolean value.
Kotlin Data Class and copy Function
Objects that are created from a data-class have a built in function called copy
. The copy() function let us to copy an object of a data type and creates a new one as a result.
Note that using this function, we can also change the value of one or more properties of the target object. In this case, the original object’s values won’t change and only the new one will have the new values.
Example: using the copy function in Kotlin
data class Person(var firstName:String, var lastName:String){} fun main(){ var person = Person("John","Doe") var secondPerson = person.copy(firstName = "Jack") println(person.firstName) println(secondPerson.firstName) }
Output:
John Jack
Note that here we have copied the value of the person object and along the way also changed the value of the firstName
property as well. If we wanted, we could also change the value of the lastName property too.
Data Class and componentN Functions
When creating a data class, Kotlin compiler automatically adds a set of functions to the class that we can use them as an alternate way of accessing the properties of that function. These are known as componentN function.
The N part here is actually a number! For example, if the target data class has 4 properties, then the compiler will add 4 functions with the names:
component1() component2() component3() component4()
So here, calling the first function will return the value of the first property, the second function returns the value of the second property and so on…
At first, these functions might seem silly, but actually Kotlin itself uses these functions automatically when we want to destruct a data class object (which is covered in the next section).
Example: using componentN functions in Kotlin
data class Person(var firstName:String, var lastName:String){} fun main(){ var person = Person("John","Doe") var secondPerson = person.copy(firstName = "Jack") println(person.component1()) println(secondPerson.component2()) }
Output:
John Doe
Kotlin Data Class and Primary Constructor Parameters
So far, every property we’ve set for a data class was in its primary constructor using the var
and let
.
But of course, you can create these properties within the body of the data classes as well.
But the important note to remember is that when creating a property inside the body of a data class, no componentN will be created for that property!
For example, if a data class has 3 properties but defined in its body and not as part of its primary constructor, then no componentN will be created for those properties in the data-class.
This means if you call the component1() function on an object that is created from such data class type, you’ll get error!
FYI: you can’t create parameters for the primary constructor of a data class without the use of val or var keyword.
Example: parameters in the primary constructor and data class
data class Person(val firstName:String, val lastName:String){ var age = 10 } fun main(){ var person = Person("John","Doe") println(person.component1()) println(person.component2()) println(person.component3()) }
Output:
error: unresolved reference. None of the following candidates is applicable because of receiver type mismatch: public inline operator fun <T> Array<out TypeVariable(T)>.component3(): TypeVariable(T) defined in kotlin.collections
As you can see, the component3()
function caused us an error because we have the third property declared inside the body of the class and so no componentN will be created for that property.