YouTip LogoYouTip

Kotlin Data Sealed Classes

# Kotlin Data Classes and Sealed Classes * * * ## Data Classes Kotlin can create a class that only holds data, using the keyword `data`: ```kotlin data class User(val name: String, val age: Int) The compiler automatically derives the following member functions from all declared properties in the primary constructor: * `equals()` / `hashCode()` * `toString()` format like `"User(name=John, age=42)"` * `componentN() functions` corresponding to the properties, in the order of declaration * `copy()` function If any of these functions are explicitly defined in the class body or inherited from a superclass, they will not be generated. To ensure consistent and meaningful generated code, data classes need to meet the following requirements: * The primary constructor must have at least one parameter. * All primary constructor parameters must be marked as `val` or `var`; * Data classes cannot be declared as `abstract`, `open`, `sealed`, or `inner`; * Data classes cannot inherit from other classes (but they can implement interfaces). ### Copying Copying is done using the `copy()` function. We can use this function to copy an object and modify some of its properties. For the `User` class above, its implementation would look something like this: ```kotlin fun copy(name: String = this.name, age: Int = this.age) = User(name, age) ### Example Using the `copy` function to copy the `User` data class and modify the `age` property: ```kotlin data class User(val name: String, val age: Int) fun main(args: Array) { val jack = User(name = "Jack", age = 1) val olderJack = jack.copy(age = 2) println(jack) println(olderJack) } The output will be: User(name=Jack, age=1) User(name=Jack, age=2) ### Data Classes and Destructuring Declarations Component functions allow data classes to be used in destructuring declarations: ```kotlin val jane = User("Jane", 35) val (name, age) = jane println("$name, $age years of age") // prints "Jane, 35 years of age" ### Standard Data Classes The standard library provides `Pair` and `Triple`. In most cases, named data classes are a better design choice because they make the code more readable and provide meaningful names and properties. * * * ## Sealed Classes Sealed classes are used to represent restricted class hierarchies: when a value can have one of a limited number of types, but no other type. In a sense, they are an extension of enum classes: the set of values for an enum type is also restricted, but each enum constant exists only as a single instance, whereas a subclass of a sealed class can have multiple instances that can contain state. To declare a sealed class, use the `sealed` modifier on the class. A sealed class can have subclasses, but all of them must be nested within the sealed class. `sealed` cannot be applied to interfaces, abstract classes (it will produce a warning, but no compilation error). ```kotlin sealed class Expr data class Const(val number: Double) : Expr() data class Sum(val e1: Expr, val e2: Expr) : Expr() object NotANumber : Expr() fun eval(expr: Expr): Double = when (expr) { is Const -> expr.number is Sum -> eval(expr.e1) + eval(expr.e2) NotANumber -> Double.NaN } The key benefit of using sealed classes is when using `when` expressions. If you can verify that the statement covers all cases, you don't need to add an `else` clause to the statement. ```kotlin fun eval(expr: Expr): Double = when(expr) { is Expr.Const -> expr.number is Expr.Sum -> eval(expr.e1) + eval(expr.e2) Expr.NotANumber -> Double.NaN // No `else` clause is needed because we have covered all cases }
← Kotlin Enum ClassesKotlin Interface β†’