Android Academy · Lesson

Data Classes & Sealed Classes

Use data classes for value-based equality and copy(), and sealed classes for exhaustive type hierarchies and clean state modeling.

Lesson 3 of 413 steps

Data Classes & Sealed Classes is a free Android Academy lesson on CoddyKit. This is lesson 3 of 4. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the Android Academy learning path, and your progress syncs across the web and the CoddyKit app. The Android Academy course includes 4 lessons in total.

What Are Data Classes?

A data class in Kotlin is a class whose primary purpose is to hold data. The compiler automatically generates useful methods for you:

  • equals() — compare two instances by value
  • hashCode() — consistent hash based on properties
  • toString() — readable string representation
  • copy() — create a modified copy
  • Destructuring support

Declaring a Data Class

Add the data keyword before class. All properties must be in the primary constructor:

data class User(val id: Int, val name: String, val email: String)

fun main() {
    val u1 = User(1, "Alice", "alice@example.com")
    val u2 = User(1, "Alice", "alice@example.com")

    println(u1)          // User(id=1, name=Alice, email=alice@example.com)
    println(u1 == u2)    // true  (value equality)
    println(u1 === u2)   // false (different objects)
}

copy() — Modify One Field

copy() creates a new instance with some properties changed. The original is not modified (immutability):

data class Product(val name: String, val price: Double, val inStock: Boolean)

fun main() {
    val original = Product("Laptop", 999.0, true)

    // Only change the price; keep everything else
    val onSale = original.copy(price = 799.0)

    println(original)  // Product(name=Laptop, price=999.0, inStock=true)
    println(onSale)    // Product(name=Laptop, price=799.0, inStock=true)
}

Destructuring Declarations

Data classes support destructuring — unpack properties into variables using componentN() functions generated by the compiler:

data class Point(val x: Int, val y: Int)

fun main() {
    val point = Point(10, 20)

    // Destructure into separate variables
    val (x, y) = point
    println("x=$x, y=$y")   // x=10, y=20

    // Also works in for loops with maps
    val scores = mapOf("Alice" to 95, "Bob" to 88)
    for ((name, score) in scores) {
        println("$name: $score")
    }
}

What Are Sealed Classes?

A sealed class is a restricted class hierarchy — all subclasses must be defined in the same file. This makes the set of possible types known at compile time.

Use sealed classes to represent a finite set of states, like network results, UI states, or navigation events.

Sealed Class Syntax

Declare subclasses directly inside or in the same file:

sealed class NetworkResult<out T> {
    data class Success<T>(val data: T) : NetworkResult<T>()
    data class Error(val message: String, val code: Int = 0) : NetworkResult<Nothing>()
    object Loading : NetworkResult<Nothing>()
}

fun handle(result: NetworkResult<String>) {
    when (result) {
        is NetworkResult.Success -> println("Data: ${result.data}")
        is NetworkResult.Error  -> println("Error ${result.code}: ${result.message}")
        NetworkResult.Loading   -> println("Loading...")
    }
}

Sealed Class + when (Exhaustive)

The power of sealed classes: when is exhaustive. The compiler forces you to handle every subtype — no forgotten cases:

sealed class UiState {
    object Loading : UiState()
    data class Success(val message: String) : UiState()
    data class Error(val error: String) : UiState()
}

fun render(state: UiState): String = when (state) {
    is UiState.Loading      -> "Showing spinner"
    is UiState.Success      -> "Show: ${state.message}"
    is UiState.Error        -> "Error: ${state.error}"
    // Compiler error if you remove any branch!
}

fun main() {
    println(render(UiState.Loading))
    println(render(UiState.Success("Loaded!")))
}

Sealed Class vs Enum

Both represent a fixed set of values, but:

  • Enum — each constant is a single instance, no extra data per variant
  • Sealed class — each variant can carry different data, be a class or object

Use enum when variants need no data. Use sealed class when variants need different properties.

Object Declarations (Singletons)

object creates a singleton — one instance, created lazily, thread-safe:

object AppConfig {
    const val BASE_URL = "https://api.example.com"
    const val TIMEOUT = 30L

    fun buildUrl(path: String) = "$BASE_URL/$path"
}

fun main() {
    println(AppConfig.BASE_URL)          // https://api.example.com
    println(AppConfig.buildUrl("users")) // https://api.example.com/users
}

Companion Objects

A companion object lives inside a class and provides class-level members (like Java's static). Commonly used for factory methods:

class Token private constructor(val value: String) {
    companion object {
        fun create(raw: String): Token {
            val cleaned = raw.trim()
            require(cleaned.isNotEmpty()) { "Token must not be blank" }
            return Token(cleaned)
        }
    }
}

fun main() {
    val token = Token.create("  abc123  ")
    println(token.value)  // abc123
}

Data Classes in a Real App

Combine data classes with sealed classes for clean state modeling:

data class Post(val id: Int, val title: String, val body: String)

sealed class PostState {
    object Loading : PostState()
    data class Loaded(val posts: List<Post>) : PostState()
    data class Failed(val reason: String) : PostState()
}

fun showState(state: PostState) = when (state) {
    PostState.Loading        -> println("Fetching posts...")
    is PostState.Loaded      -> println("${state.posts.size} posts loaded")
    is PostState.Failed      -> println("Failed: ${state.reason}")
}

fun main() {
    showState(PostState.Loaded(listOf(
        Post(1, "Hello", "World"),
        Post(2, "Kotlin", "Rocks")
    )))
}

Quick Check

Which statement best describes what makes sealed classes different from regular abstract classes?

Recap: Data & Sealed Classes

You now have two powerful Kotlin tools:

  • data class — value-based equality, copy(), destructuring, auto-generated toString()
  • sealed class — finite type hierarchy, exhaustive when, each variant can carry its own data
  • object — singleton, companion objects for factory methods

Together, these patterns replace Java boilerplate and enable clean, safe state modeling.

Free to start

Learn Kotlin with an AI tutor — free

Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.

Courses
36
Lessons
152

Frequently Asked Questions

Is the “Data Classes & Sealed Classes” lesson free?

Yes — any 3 lessons of the Android Academy learning path, including “Data Classes & Sealed Classes”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The Android Academy course includes 4 lessons in total.

What will I learn in “Data Classes & Sealed Classes”?

Use data classes for value-based equality and copy(), and sealed classes for exhaustive type hierarchies and clean state modeling. You practise Android Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Android Academy?

No prior experience is required. Android Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 3 of 4.

How long does the “Data Classes & Sealed Classes” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Android Academy lesson?

Yes. Every Android Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Null Safety
  2. Classes & Objects
  3. Data Classes & Sealed Classes
  4. Extension Functions & Higher-Order Functions
← Back to Android Academy