Classes
Kotlin classes are concise by default. Primary constructors live on the class header; val / var in the constructor are auto-generated properties. data class, sealed class, and object cover most patterns.
data, sealed, object, by
EXAMPLE
// 1) Standard class with primary ctor + property
class User(val name: String, var email: String) {
val createdAt = System.currentTimeMillis()
init {
require(email.contains('@')) { "invalid email" }
}
fun verify() = println("\$name verified")
}
val u = User("Ada", "ada@example.com")
u.verify()
// 2) data class — equals, hashCode, toString, copy() generated
data class Money(val amount: Double, val currency: String)
val price = Money(9.99, "AUD")
val bumped = price.copy(amount = 11.99) // copy with override
println(price == Money(9.99, "AUD")) // true — value equality
// 3) sealed class — closed hierarchy, exhaustive when
sealed class Result<out T> {
data class Ok<T>(val value: T) : Result<T>()
data class Err(val message: String) : Result<Nothing>()
object Loading : Result<Nothing>()
}
fun render(r: Result<String>) = when (r) { // exhaustive
is Result.Ok -> "got \${r.value}"
is Result.Err -> "failed: \${r.message}"
Result.Loading -> "…"
}
// 4) object — singleton
object Logger {
fun info(msg: String) = println("[info] \$msg")
}
Logger.info("hello")
// 5) companion object — static-like members on a class
class User2 private constructor(val id: Int) {
companion object {
fun create(id: Int): User2 = User2(id)
const val MAX = 1_000
}
}
User2.create(1)
// 6) by — delegation
interface Repo { fun load(id: Int): String }
class InMemoryRepo : Repo { override fun load(id: Int) = "in-mem(\$id)" }
class Service(repo: Repo) : Repo by repo // delegates all Repo methods
val svc = Service(InMemoryRepo())
println(svc.load(7))
// 7) Inheritance — open / override
open class Animal { open fun sound() = "?" }
class Cat : Animal() {
override fun sound() = "meow"
}
// 8) Abstract
abstract class Shape {
abstract val area: Double
override fun toString() = "\${this::class.simpleName}(area=\$area)"
}
class Rect(val w: Double, val h: Double) : Shape() {
override val area: Double get() = w * h
}
// 9) Properties — backing fields + getters / setters
class Counter {
var count: Int = 0
private set // read-only outside
fun bump() { count++ }
}
Why it matters
sealed class + when gives you exhaustive pattern matching at compile time. Adding a new variant forces every site to handle it — the compiler is your code-review.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
class User(val name: String, var age: Int) {
fun greet() = "hi, $name"
}
val u = User("Ada", 36)
println(u.greet())
Try it Yourself »
Discussion
Loading…