How it works
The explanation, with examples you can run.
On the JVM: ordinary classes
kotlinc (or Gradle's Kotlin plugin) emits .class files that the JVM loads like any others, plus a dependency on the small kotlin-stdlib jar. A few things have to be mapped onto what the JVM has:
// File: Prices.ktpackage shop const val VAT = 0.25 // a static final field on PricesKt fun withVat(net: Double): Double = net * (1 + VAT) // static method PricesKt.withVat class Basket(val items: List<Double>) { // final class, private field + getter getItems() fun total() = items.sumOf(::withVat)} fun main() { println(Basket(listOf(10.0, 20.0)).total()) // 37.5}- Top-level functions and properties live in a class named after the file:
PricesKt. - Classes are final and their methods are not overridable unless you write
open. - Properties become a private field plus getter and setter methods.
- Null checks: for every non-null parameter of a public function, the compiler adds a check on entry, because a Java caller could pass
null. That's why the NullPointerException names the parameter.
You can see all of this with javap -c on the compiled classes, or in the IDE with Show Kotlin Bytecode, which also decompiles it back to Java.
Other targets
Kotlin/Native compiles to a standalone binary with its own runtime and garbage collector, and can export a framework that Swift and Objective-C can call. Kotlin Multiplatform builds on that: common code is compiled for each target, and expect/actual declarations fill in the platform-specific parts. The language is the same everywhere, but the libraries differ: java.* exists only on the JVM.
K2: the new front end
Kotlin 2.0 (May 2024) made K2 the default compiler front end on every target. It is a rewrite of the analysis that came before, built around one internal representation for all platforms. You mostly notice it as faster compilation and as smart casts that work where they used to fail, for example after a check on a local variable that is later captured, or after || checks on two types. A few edge cases that the old compiler accepted are now errors; the migration guide lists them.
What the compiler adds
Many Kotlin features are pure compiler work with no runtime cost: data class methods, default arguments (an extra synthetic overload with a bit mask), inline functions copied into the caller, string templates turned into ordinary string concatenation. When something looks magic, the bytecode viewer usually shows a plain-Java shape behind it.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.