What does @JvmOverloads do, and why is it needed when Kotlin functions with default arguments are called from Java?
answer
- Java can't see Kotlin defaults
- Generates trailing overloads right-to-left
- Works on funs, methods, constructors
- @JvmOverloads constructor(...) placement
- Non-trailing defaults still unskippable from Java
basics
~10 sJava does not understand Kotlin default arguments, so it sees only the full-parameter version. Adding @JvmOverloads tells the compiler to generate extra Java-visible overloads, one per defaulted parameter, so Java callers can omit them.
solid answer
~40 sKotlin default arguments are a Kotlin-only feature: the compiler emits a single method plus a synthetic dispatcher, so a Java caller sees only the function with the full parameter list and cannot omit defaulted arguments. Annotating the function (or constructor) with @JvmOverloads makes the compiler generate a series of real JVM overloads, each dropping trailing defaulted parameters from right to left and forwarding to the full method using the defaults. For fun f(a: Int, b: Int = 1, c: Int = 2) it generates f(a), f(a, b), and f(a, b, c). Java can then call any of them. It works on top-level functions, member functions, and constructors. It only produces overloads by removing trailing parameters, so non-trailing defaults still can't be skipped from Java. Pure-Kotlin code never needs it.
code
kotlin · 8 lines@JvmOverloads
fun rect(width: Int, height: Int = width, filled: Boolean = false): String =
"$width x $height filled=$filled"
// From Java you could now call:
// rect(10) -> 10 x 10 filled=false
// rect(10, 5) -> 10 x 5 filled=false
// rect(10, 5, true) -> 10 x 5 filled=truego deeper
Knows @JvmOverloads exists for Java interop with defaults.
Explains the synthetic-method gap and that it generates trailing overloads right-to-left.
Knows the constructor placement, the non-trailing limitation, and the bytecode/API-surface cost tradeoff.
Weighs interop API design, Android View constructor patterns, and binary-compatibility implications of generated overloads.
## The problem Default arguments are a **Kotlin language feature**, not a JVM feature. When the Kotlin compiler sees `fun f(a: Int, b: Int = 1)`, it emits a single bytecode method `f(int, int)` plus a hidden synthetic `f$default(...)` dispatcher that Kotlin call sites use. **Java has no idea** about defaults or the synthetic dispatcher, so from Java you can only call the full `f(a, b)` — you cannot omit `b`. ## What @JvmOverloads does Annotating with **`@JvmOverloads`** instructs the compiler to additionally generate **real overloaded methods** in bytecode — one for each *trailing* defaulted parameter dropped — each forwarding to the full implementation with the appropriate defaults filled in. ```kotlin @JvmOverloads fun f(a: Int, b: Int = 1, c: Int = 2) { /* ... */ } ``` Generates Java-visible overloads: - `f(int a)` → calls `f(a, 1, 2)` - `f(int a, int b)` → calls `f(a, b, 2)` - `f(int a, int b, int c)` (the original) Now Java can write `f(5)`, `f(5, 9)`, or `f(5, 9, 0)`. ## Key rules - It drops **trailing** parameters from **right to left** only. A *non-trailing* defaulted parameter still cannot be skipped from Java. - It applies to **top-level functions, member functions, and constructors** (very common on Android `View` subclasses). - On a **constructor**, place it after visibility/annotations: `class V @JvmOverloads constructor(...)`. - For an **abstract/open** function, `@JvmOverloads` does not generate overloads for the abstract declaration in the same way; it generates overloads for concrete methods. - **Pure Kotlin doesn't need it** — Kotlin call sites already honor defaults directly. ## Why not always add it Each overload is extra bytecode and extra public API surface; add `@JvmOverloads` only where Java/Android interop actually needs to omit arguments.
- Can @JvmOverloads let Java skip a default that is NOT the last parameter?No. It only generates overloads by dropping trailing parameters right-to-left, so a non-trailing default remains required from Java.
- Where do you put @JvmOverloads on a constructor?Before the constructor keyword: class V @JvmOverloads constructor(ctx: Context, attrs: AttributeSet? = null).
Like printing several shorter versions of a long form so people who only fill the first fields still have a valid form to submit.
saying these in an interview costs you the question
- Thinking pure-Kotlin code needs @JvmOverloads
- Believing it lets Java skip arbitrary (non-trailing) parameters
- Not knowing it applies to constructors
- Confusing it with @JvmStatic or @JvmName