Show how to resolve a generic-erasure platform clash for two overloads using @JvmName, and explain what each annotation changes.
answer
- Rename at least one side with @JvmName
- Kotlin name unchanged; Java sees new name
- Use @get:/@set:JvmName for accessors
- Cannot rename open/override members
- @file:JvmName renames the facade class
basics
~10 sPut @JvmName with a different name on at least one of the clashing functions. That gives each a unique method name in the compiled code, so the JVM no longer sees a duplicate.
solid answer
~40 sAnnotate the clashing declarations with `@JvmName("uniqueName")` so each emits a distinct JVM method name. You only strictly need to rename one of the two, but renaming both makes the Java-facing API clearer. `@JvmName` targets functions, property getters/setters (via use-site targets `@get:JvmName`/`@set:JvmName`), and file facade classes (`@file:JvmName`). It changes only the generated bytecode symbol; Kotlin still resolves the original Kotlin name, so Kotlin call sites are untouched, while Java callers must use the new name. A caveat: `@JvmName` cannot be applied to `open`/`override` members participating in inheritance, because renaming would break the virtual method table — so you cannot rename overrides this way.
code
kotlin · 8 lines@JvmName("filterInts")
fun filter(xs: List<Int>): List<Int> = xs.filter { it > 0 }
@JvmName("filterStrings")
fun filter(xs: List<String>): List<String> = xs.filter { it.isNotEmpty() }
// Kotlin: filter(listOf(1,-2)) / filter(listOf("a",""))
// Java: filterInts(...) / filterStrings(...)go deeper
Knows @JvmName fixes the clash and can copy the pattern.
Applies it to one or both sides, explains Kotlin-vs-Java visibility, and uses accessor targets.
Knows the override restriction and chooses between @JvmName and distinct Kotlin names per API audience.
Designs the public surface so Java consumers get clean, documented names and avoids needing the workaround.
## The setup Generic erasure collapses these to one descriptor: ```kotlin fun ids(xs: List<Int>): String = xs.joinToString() // ids(List) fun ids(xs: List<String>): String = xs.joinToString() // ids(List) -> CLASH ``` ## The fix ```kotlin @JvmName("idsFromInts") fun ids(xs: List<Int>): String = xs.joinToString() @JvmName("idsFromStrings") fun ids(xs: List<String>): String = xs.joinToString() ``` Result in bytecode: `idsFromInts(List)` and `idsFromStrings(List)` — distinct descriptors. From **Kotlin** you call `ids(listOf(1,2))` and `ids(listOf("a"))` exactly as before. From **Java** you call `idsFromInts(...)` / `idsFromStrings(...)`. ## What @JvmName can target - **Top-level / member functions**: `@JvmName("...")`. - **Property accessors** via use-site targets: `@get:JvmName("...")`, `@set:JvmName("...")` — useful when a generated getter collides. - **File facade class**: `@file:JvmName("Utils")` at the top of a file renames the synthetic `XxxKt` class. ## Important caveats - You can rename just **one** side and the clash disappears, but renaming both yields a self-documenting Java API. - `@JvmName` is **forbidden on `open`, `abstract`, and `override` members** that take part in virtual dispatch — renaming would corrupt overriding, so the compiler rejects it. Restructure (e.g. delegate to differently named private helpers) instead. - It does **not** change overload resolution within Kotlin; the Kotlin name is what Kotlin sees. - Alternative when you don't need both names visible: simply give the functions different **Kotlin** names — no annotation needed. ## Mental model Think of `@JvmName` as a label printer for the bytecode: it swaps the sticker the JVM reads while leaving the Kotlin-side name intact.
- Can you put @JvmName on an overriding function to dodge a clash?No. The compiler forbids @JvmName on open/abstract/override members because it would break virtual dispatch. Refactor to non-virtual helpers or give distinct Kotlin names instead.
- Is renaming only one of the two functions enough?Yes — once the descriptors differ, the clash is gone. Renaming both is just clearer for Java consumers.
saying these in an interview costs you the question
- Believing @JvmName changes Kotlin-side resolution
- Trying to apply @JvmName to an override and assuming it compiles
- Forgetting accessors need @get:/@set: use-site targets
- Claiming you must annotate both functions