skip to content

What does the @JvmOverloads annotation do, and why is it needed for Java callers?

level: juniorimportance: must knowfreq 70%

answer

  1. Java can't see Kotlin defaults
  2. Generates real JVM overloads
  3. Drops defaults right-to-left
  4. N+1 overloads
  5. Interop convenience, no change for Kotlin

basics

~10 s

Java cannot use Kotlin's default argument values. @JvmOverloads tells the compiler to also generate extra Java-visible overloads, one per default-parameter combination, so Java code can call the function while leaving some arguments out.

solid answer

~40 s

Kotlin default parameter values live in the Kotlin function and Java callers can't supply them, so from Java you'd always have to pass every argument. Adding @JvmOverloads to a function or constructor makes the compiler emit additional JVM-visible overloaded methods/constructors: one for the full signature plus one for each trailing-defaults combination, dropping defaulted parameters from the right. So fun greet(name: String, greeting: String = "Hi", loud: Boolean = false) produces three Java-callable overloads: greet(name), greet(name, greeting), greet(name, greeting, loud). It changes nothing for Kotlin callers — they already use defaults directly. It's purely an interop convenience for Java (and other JVM languages) consuming the Kotlin API.

code

kotlin · 5 lines
kotlin
@JvmOverloads
fun connect(host: String, port: Int = 8080, secure: Boolean = false) {
    // ...
}
// Java gets: connect(host), connect(host, port), connect(host, port, secure)

go deeper

for a junior

Knows Java can't use Kotlin defaults and that @JvmOverloads creates extra Java-callable overloads.

for a middle

Can predict exactly which overloads are generated and that defaults drop right-to-left.

for a senior

Explains it's compiler-generated forwarding methods, applies to constructors, and is a no-op for Kotlin callers.

for a principal

Frames it as an API-surface/interop design decision and weighs it against alternatives like builders or explicit overloads.

## The problem In Kotlin you can give parameters **default values**: ```kotlin fun greet(name: String, greeting: String = "Hi", loud: Boolean = false): String { val msg = "$greeting, $name" return if (loud) msg.uppercase() else msg } ``` Kotlin callers can omit defaulted arguments: `greet("Ada")`. But this default mechanism is a **Kotlin compiler feature**, not a JVM feature. The JVM has no notion of default arguments. Under the hood Kotlin compiles ONE method `greet(String, String, boolean)` plus a hidden synthetic helper that fills in defaults — but Java cannot call that helper conveniently. So from **Java**, by default you must pass every argument: ```java Kt.greet("Ada", "Hi", false); // must supply all three ``` ## What @JvmOverloads does Annotating the function (or constructor) tells the Kotlin compiler to **generate extra real overloads** visible to the JVM — one per combination of trailing defaults, removing defaulted parameters **from right to left**: ```kotlin @JvmOverloads fun greet(name: String, greeting: String = "Hi", loud: Boolean = false): String { /* ... */ } ``` Now Java sees three methods: ```java Kt.greet("Ada"); // greeting="Hi", loud=false Kt.greet("Ada", "Hello"); // loud=false Kt.greet("Ada", "Hello", true); ``` Each generated overload simply forwards to the full method using the default values. ## Key facts - It generates **N+1** overloads where N is the number of parameters with defaults (the full one plus one per removed trailing default). - Defaults are dropped **right-to-left only** — there is no overload that keeps `loud` but drops `greeting`. - It works on **top-level functions, member functions, and constructors**. - For **Kotlin callers nothing changes**: they keep using the single function with named/default arguments. - It is purely a JVM **interop** affordance — useful for Java, Android framework code (e.g. custom `View` constructors), Spring, mocking frameworks, etc. ## Without vs with Without the annotation, Java gets only the maximal-arity method. With it, Java gets a friendly ladder of overloads matching what Kotlin callers enjoy via defaults.

  • Does @JvmOverloads change anything for Kotlin callers?
    No. Kotlin callers still use the single function with default and named arguments; the extra overloads are only emitted for JVM/Java visibility.
  • How many methods are generated if there are 2 defaulted parameters?
    Three: the full-arity method plus one dropping the last default and one dropping both — i.e. N+1 where N=2.

It's like a restaurant translating a 'build-your-own combo' into a printed menu of fixed combos, because Java customers can't order off the custom builder.

saying these in an interview costs you the question

  • Claiming Java can call Kotlin default arguments directly without it
  • Saying it changes behavior or signatures for Kotlin callers
  • Thinking it generates overloads for every subset of parameters, not just trailing ones
  • Confusing it with @JvmStatic or @JvmName

context