Kotlin and Java compile to the same JVM bytecode, so calling Java methods and classes from Kotlin (and vice versa) works directly, with no wrapper layer needed. The genuine complication is nullability: Java has no built-in concept of nullable vs. non-null types (absent explicit @Nullable/@NonNull annotations), so a value returned from Java code is treated in Kotlin as a platform type — Kotlin simply doesn't know if it can be null, and suspends its usual compile-time null-checking for that value, trusting the programmer to handle it correctly. @JvmStatic exposes a companion object member as a genuine static method callable from Java; @JvmOverloads generates the multiple overloaded methods Java needs to approximate Kotlin's default-parameter functions.
Platform types: the real gap in null safety
String! means Kotlin genuinely doesn't know if getProperty can return null — it compiles as EITHER a nullable or non-null String, entirely without a compile-time safety net, until the actual runtime behavior of the Java method is understood and handled deliberately.
// calling a Java method: System.getProperty(String) returns java.lang.String
val value = System.getProperty("some.key") // type shown by tooling as: String! (platform type)
// Kotlin has NO compile-time guarantee here — value might genuinely be null
println(value.length) // compiles fine — but could throw NullPointerException at runtime,
// exactly the crash Kotlin's own types normally prevent@JvmStatic: exposing a real static method to Java
Without @JvmStatic, Java code would need to write Companion.create(...) to call it — the annotation makes it a genuine static method, callable the natural way Java code expects.
class Config {
companion object {
@JvmStatic
fun create(): Config = Config()
}
}
// from Java: Config.create() — natural, thanks to @JvmStatic
// without it, Java would need: Config.Companion.create()@JvmOverloads: default parameters, made visible to Java
Java has no concept of a default parameter value at all — @JvmOverloads generates the actual overloaded method variants Java code needs to call this function with fewer arguments.
class Greeter {
@JvmOverloads
fun greet(name: String, greeting: String = "Hello") {
println("$greeting, $name!")
}
}
// from Java, BOTH of these now exist and are callable:
// greeter.greet("Alice");
// greeter.greet("Alice", "Welcome");