Chapter 11: Classes & Objects β Advanced
Classes & Objects β Advanced β this is the chapter where Kotlin classes become really powerful, concise, and production-ready! π
In this chapter weβll cover the most famous and most loved advanced class features in Kotlin β the ones that make developers say: βWow, this is why I love Kotlin!β
Weβll go super slowly, like weβre sitting together in a quiet Bandra cafΓ© with cutting chai β β every concept with real-life analogies, complete runnable examples, step-by-step explanations, tables, common mistakes with fixes, and tons of code you can copy-paste and run right now.
Letβs dive in!
1. Data Classes (data class) β The Most Loved Feature
Data classes are special classes whose main purpose is to hold data β like DTOs, models, entities.
When you mark a class with data, Kotlin automatically generates a bunch of very useful methods:
- toString() β beautiful readable output
- equals() & hashCode() β based on all properties
- copy() β easy way to create modified copy
- componentN() β destructuring declarations
Syntax:
|
0 1 2 3 4 5 6 |
data class Person(val name: String, val age: Int, val city: String) |
Normal class vs data class (huge difference!)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
// Normal class class NormalPerson(val name: String, val age: Int) { // You get nothing for free } // Data class data class DataPerson(val name: String, val age: Int) |
Example β All magic features in action
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
fun main() { val p1 = DataPerson("Webliance", 25) val p2 = DataPerson("Webliance", 25) val p3 = DataPerson("Amit", 22) // 1. Beautiful toString() println(p1) // DataPerson(name=Webliance, age=25) // 2. Structural equality (equals & hashCode based on properties) println(p1 == p2) // true println(p1 == p3) // false // 3. copy() β create modified copy (very common!) val p4 = p1.copy(age = 26) // Copy with changed age println(p4) // DataPerson(name=Webliance, age=26) // 4. componentN() β destructuring val (name, age) = p1 println("Name: $name, Age: $age") // Name: Webliance, Age: 25 } |
When to use data class?
- DTOs / API responses
- Data models (Room entities, JSON models)
- Any class whose identity is defined by its data (not behavior)
Rules:
- Primary constructor must have at least one parameter
- All primary constructor parameters must be val or var (properties)
- Cannot be open, abstract, or inner
2. object β Singletons (The Easy Singleton Pattern)
In Kotlin, object creates a singleton β exactly one instance of the class, created lazily (when first used).
Real-life analogy: object is like the sun β there is only one sun, and everyone can access it directly.
Syntax:
|
0 1 2 3 4 5 6 7 8 9 10 |
object Logger { fun log(message: String) { println("LOG: $message β {java.time.LocalDateTime.now()}") } } |
Usage:
|
0 1 2 3 4 5 6 7 8 9 |
fun main() { Logger.log("App started") // No new, no getInstance() Logger.log("User logged in") } |
Very common use cases:
- Utility classes (no state)
- Singletons (database connection pool, configuration, logger)
- Companion objects (next topic)
3. companion object β Static Members in Kotlin
Kotlin has no static keyword β instead we use companion object inside a class.
companion object members behave like static in Java.
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class MathUtils { companion object { const val PI = 3.14159 fun square(n: Int) = n * n fun cube(n: Int) = n * n * n } } |
Usage:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
fun main() { println(MathUtils.PI) // No instance needed println(MathUtils.square(5)) // 25 println(MathUtils.cube(3)) // 27 // You can still create instance val utils = MathUtils() // but no need for static methods } |
Named companion object (optional β for clarity)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class Database { companion object Factory { fun createConnection(): String = "Connected to DB!" } } fun main() { println(Database.Factory.createConnection()) // or just Database.createConnection() β both work } |
4. Enum Classes β Type-Safe Constants
Enums in Kotlin are full classes β they can have properties, methods, implement interfaces!
Basic enum
|
0 1 2 3 4 5 6 7 8 |
enum class Day { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY } |
Advanced enum with properties & methods
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
enum class TrafficLight(val color: String, val action: String, val durationSec: Int) { RED("Red", "STOP", 30), YELLOW("Yellow", "WAIT", 5), GREEN("Green", "GO", 45); fun next(): TrafficLight { return when (this) { RED -> YELLOW YELLOW -> GREEN GREEN -> RED } } } |
Usage:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
fun main() { val light = TrafficLight.RED println("${light.color} β ${light.action} for ${light.durationSec} seconds") val nextLight = light.next() println("Next: ${nextLight.color}") } |
5. Inline Classes (Value Classes) β Kotlin 1.5+ (Very Lightweight Wrappers)
Inline classes (also called value classes) are zero-cost wrappers β the compiler removes them at runtime.
Use case: You want to add type safety without performance cost.
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@JvmInline value class Email(val value: String) { init { require(value.contains("@")) { "Invalid email" } } } @JvmInline value class UserId(val value: Long) |
Usage:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
fun main() { val email = Email("webliance@example.com") // val wrong = Email("invalid") β crashes at init! val id = UserId(1001L) println("Email: ${email.value}") println("User ID: ${id.value}") } |
At runtime β Email and UserId disappear β itβs just String and Long β zero overhead!
Quick Recap Table (Your Cheat Sheet)
| Feature | Kotlin Way (Best Practice) | Key Benefit |
|---|---|---|
| Data class | data class Person(val name: String, val age: Int) | Auto toString(), equals(), copy(), destructuring |
| object | object Logger { … } | Singleton β one instance |
| companion object | companion object { … } | Static members without static |
| Enum class | enum class Day { MONDAY, … } | Type-safe constants + properties/methods |
| Inline / value class | @JvmInline value class Email(val value: String) | Type safety with zero runtime cost |
Common Newbie Mistakes & Fixes
| Mistake | Problem | Fix |
|---|---|---|
| Forgetting data keyword | No auto methods (toString, equals, copy) | Always use data class for data holders |
| Making data class with no properties | Compile error | Primary constructor must have at least 1 param |
| Using object inside function | Not allowed | object must be top-level or nested |
| Forgetting @JvmInline on value class | Not inlined at runtime | Always add @JvmInline |
| Not using copy() for data classes | Manual copying β error-prone | Use person.copy(age = 26) |
Homework for You (Letβs Make It Fun!)
- Basic Create a data class Book(val title: String, val author: String, val price: Double) β create 3 books β print them.
- Medium Create data class Product(val id: Int, val name: String, val price: Double) β use copy() to create a discounted version.
- Advanced Create object Config with constants APP_NAME, VERSION, and a function printInfo().
- Fun Create enum class PizzaSize(val inches: Int, val slices: Int) with SMALL, MEDIUM, LARGE β add method price().
- Challenge Create an inline class PositiveInt(val value: Int) with validation in init (value > 0).
Youβve just mastered Kotlinβs most powerful class features β now you can write clean, safe, and modern Kotlin code!
