Introduction
Kotlin compiles to JVM bytecode, which means Kotlin code can call Java code directly and Java code can call Kotlin code directly. This seamless interoperability is one of the biggest reasons Kotlin gained rapid adoption: teams could introduce it incrementally into existing Java or Android codebases without rewriting everything at once.
Cricket analogy: Like an overseas player joining a domestic T20 franchise mid-season and slotting straight into the batting order without the whole squad needing to relearn the game, Kotlin code calls Java code directly on the same JVM.
Syntax
// Kotlin calling a Java class
val list = java.util.ArrayList<String>()
list.add("Kotlin")
// Exposing Kotlin members as true Java statics
class Config {
companion object {
@JvmStatic
fun defaultName() = "SkillVeris"
@JvmField
val VERSION = "1.0"
}
}Explanation
Because Kotlin and Java both target the JVM, Kotlin classes and functions are visible to Java code, sometimes with naming adjustments handled by annotations. Companion object members are not true static members by default; the @JvmStatic annotation exposes a companion function as a real static method callable from Java, while @JvmField exposes a property as a plain static field instead of a getter/setter pair. When Kotlin consumes Java APIs, types whose nullability is unknown appear as platform types, notated internally as something like String!. The Kotlin compiler does not enforce null-safety checks on platform types, so the developer is responsible for handling potential nulls correctly.
Cricket analogy: Like a team's vice-captain (companion object) who can call plays from the pavilion without being on the official playing XI (a true static member), @JvmStatic promotes that vice-captain to an on-field captain Java can address directly.
Example
// Java class (User.java)
// public class User {
// public String getName() { return null; }
// }
fun greet(user: User) {
val name = user.name // platform type String!, no compile-time null check
println("Hello, ${name.uppercase()}") // may throw NullPointerException at runtime
}
// Output:
// Exception in thread "main" java.lang.NullPointerExceptionKey Takeaways
- Kotlin compiles to JVM bytecode, enabling two-way calls between Kotlin and Java.
- @JvmStatic exposes companion object functions as true Java static methods.
- @JvmField exposes a Kotlin property as a plain Java static field.
- Platform types like String! represent Java types with unverified nullability.
- The compiler does not enforce null-safety on platform types, shifting responsibility to the developer.
- This interop enabled incremental Kotlin adoption in existing Java and Android codebases.
Practice what you learned
1. Why can Kotlin and Java call each other's code directly?
2. What does @JvmStatic do?
3. What is a platform type in Kotlin, such as String!?
4. Why was Kotlin-Java interoperability important for adoption?
5. What does @JvmField do differently from a normal Kotlin property?
Was this page helpful?
You May Also Like
Null Safety in Kotlin
Kotlin's type system distinguishes nullable from non-nullable types at compile time, eliminating most NullPointerExceptions before code ever runs.
Coroutines in Kotlin
Understand how Kotlin coroutines enable lightweight asynchronous programming using suspend functions and builders.
Object Declarations and Companion Objects in Kotlin
Understand Kotlin's object keyword for singletons and companion objects for class-level, Java-static-like members.
Features of Kotlin
An overview of Kotlin's core language features, including null safety, concise syntax, and multi-paradigm support.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics