skip to content

On the JVM, how are top-level functions and properties in a file named Utils.kt compiled, and how do you call them from Java?

level: middleimportance: should knowfreq 58%

answer

  1. FileName + Kt = facade class (UtilsKt)
  2. Top-level fns -> public static methods
  3. @file:JvmName renames the facade
  4. @file:JvmMultifileClass merges files
  5. JVM has no code outside classes

basics

~10 s

Kotlin puts all top-level functions and properties from Utils.kt into a generated class called UtilsKt. From Java you call them as static methods on UtilsKt, like UtilsKt.doThing().

solid answer

~40 s

Because the JVM has no concept of code outside a class, the Kotlin compiler synthesizes a *facade* (or file) class to hold top-level functions and properties. The name is the file name with the extension stripped and Kt appended: Utils.kt becomes UtilsKt. Top-level functions become public static methods; top-level properties become static fields with static getters/setters (or just a constant for const val). From Java you write UtilsKt.format(x). You can rename the facade with @file:JvmName("Utils") placed at the top of the file before the package declaration, producing Utils instead of UtilsKt. Multiple files can merge into one facade using @file:JvmMultifileClass together with the same @JvmName. This is purely a JVM detail - from Kotlin you just call the function directly.

code

kotlin · 7 lines
kotlin
@file:JvmName("Strings")
@file:JvmMultifileClass
package com.example.text

fun reverse(s: String): String = s.reversed()
const val EMPTY = ""
// Java: Strings.reverse("ab"); Strings.EMPTY;

go deeper

for a junior

Knows top-level functions become static methods on a class named like the file plus Kt.

for a middle

States the exact UtilsKt naming rule and how Java calls it, including const val vs val backing.

for a senior

Uses @JvmName and @JvmMultifileClass deliberately to shape a clean Java-facing API surface.

for a principal

Weighs facade naming/merging against binary compatibility, reflection, and published-library interop stability.

## Why a facade class exists The JVM bytecode model requires every method and field to belong to a class. Kotlin lets you write top-level functions/properties, so the compiler must generate a synthetic class to host them. This generated class is called the **file facade** (or file class). ## The naming rule The facade name = file name, drop `.kt`, capitalize first letter if needed, append `Kt`. - `Utils.kt` -> `UtilsKt` - `StringHelpers.kt` -> `StringHelpersKt` If appending `Kt` would clash with a class literally named `UtilsKt` declared in the file, the compiler disambiguates, but normally you just get `<FileName>Kt`. ## What gets generated - **Top-level functions** -> `public static` methods on the facade. - **Top-level `val`/`var`** -> a private static backing field plus static `getX()` / `setX()` methods. - **Top-level `const val`** -> a `public static final` field (a true constant, inlined at call sites). ## Calling from Java ```java // Kotlin: file Utils.kt with fun format(n: Int): String String s = UtilsKt.format(42); ``` ## Customizing the name with @JvmName Place a **file-level annotation** (note the `@file:` target) above the `package` line: ```kotlin @file:JvmName("Utils") package com.example fun format(n: Int) = n.toString() ``` Now Java calls `Utils.format(42)` - the `Kt` suffix is gone. ## Merging several files into one facade Add `@file:JvmMultifileClass` to **each** file plus the **same** `@file:JvmName("Utils")`. The compiler merges their top-level members into a single `Utils` class, useful for splitting a large utility API across source files while presenting one class to Java. ```kotlin @file:JvmMultifileClass @file:JvmName("Utils") package com.example ``` ## From Kotlin you never see this Within Kotlin you call `format(42)` directly (after import). The facade is invisible; it only matters for Java interop, reflection, and stack traces.

  • Where must @file:JvmName be placed?
    As a file-level annotation at the very top of the file, before the package declaration.
  • What is the difference between a const val and a regular top-level val in the bytecode?
    const val becomes a public static final constant (inlinable); a regular val gets a private field plus a static getter method.

Kotlin's loose top-level functions are like papers on a desk; to file them in the JVM cabinet the compiler staples them into a folder labeled UtilsKt.

saying these in an interview costs you the question

  • Saying top-level functions compile to instance methods
  • Thinking the facade name is just the file name without Kt
  • Believing @JvmName can go anywhere in the file
  • Claiming you must call UtilsKt from Kotlin code too
  • Confusing JvmMultifileClass with JvmStatic

context