Open-Source Internship opportunity by OpenGenus for programmers. Apply now.
Key Takeaways (JvmOverloads, JvmField, and JvmStatic)
- `@JvmOverloads`, `@JvmField`, and `@JvmStatic` are annotations in kotlin to improve interoperability with the Java code.
- `@JvmStatic` is used to mark a companion object function or property as a static method in the generated Java bytecode.
- `@JvmOverloads` is used to generate overloads for the kotlin functions with default values in Java.
- `@JvmField` is used to mark a kotlin attribute as public fields in Java code.
In this article, we will learn about three essential annotations in Kotlin programming for improving interoperability with Java code: @JvmOverloads, @JvmField, and @JvmStatic.
Table of Content
In Kotlin Programming language, @JvmOverloads
, @JvmField
, and @JvmStatic
are annotations used for improving the interoperability with the Java code.
As Kotlin is designed with Java interoperability in mind so that Kotlin code can be used seamlessly in Java projects and vice-versa so The annotations @JvmOverloads
, @JvmField
, and @JvmStatic
in Kotlin are specifically used for improving interoperability with Java code.
Let's learn all three one by one.
JvmStatic
It is used to mark a companion object method/property as a static membets/methods in the generated Java bytecode. Now lets understand it using an example.
Without Annotation
class Engine {
companion object {
fun start() {}
}
}
Calling start
method:
In Kotlin
Engine.start()
As we can see in above code, We can access and call the start method of class Engine
directly using the class name which is the desired behaviour of the companion object.
In Java
Engine.Companion.start()
But for Java code it is little different it is not working as a static field because we are accessing the start
method using a Companion
object. Now you may have doubt what is this Companion
object? and why can't directly access it using class name as static members and methods should?
So simple answer is that Kotlin by default does not generate static members and methods but rather it store them in a object, This object is the Companion
we're using in above example.
So, In order to generate static members and methods we annotate them using JvmStatic
. Now lets see an example after annotating the method start
with the JvmStatic
.
With Annotation
class Engine {
companion object {
@JvmStatic fun start() {}
}
}
Calling start
method:
In Kotlin
Engine.start()
As we can see in above code, there is no difference for accessing and calling the start method in Kotlin is same.
In Java
Engine.start()
As we can see after the annotation we can directly access the start
method in the Java too, Because this time instead of wrapping all the objects and members inside companion object
in a Companion
object it created define the method start
as static.
JvmOverloads
In Kotlin, we can define a function or a constructor can have default parameters, but in Java, we have to define multiple versions of the function to simulate the same behavior. @JvmOverloads
annotation is used to generate these overloaded versions for Java. lets understand using an example.
Without Annotation
class Point(
x: Int = 0,
y: Int = 0,
z: Int = 0
)
Defining the class Point
In Kotlin
val p1 = Point()
val p2 = Point(x = 4)
val p3 = Point(x = 3)
val p4 = Point(x = 10, y = 11)
val p5 = Point(x = 10, y = 11, z = 2)
As we can see in the above code we can initialize class Point
in different ways as all constructor parameters have default values, Which is the the desired behaviour we want.
In Java
Point p = new Point(0, 0, 0)
As we can see in the although we have default parameters in the class constructor then also we've to pass all arguments, To overload default parameters we use JvmOverloads
With Annotation
class Point @JvmOverloads(
x: Int = 0,
y: Int = 0,
z: Int = 0
)
Defining the class Point
In Kotlin
val p1 = Point()
val p2 = Point(x = 4)
val p3 = Point(x = 3)
val p4 = Point(x = 10, y = 11)
val p5 = Point(x = 10, y = 11, z = 2)
As we can see in the above code Kotlin will have no change in initializing the class.
In Java
Point p = new Point()
Point p1 = new Point(10) // (x = 10)
Point p2 = new Point(10, 20) // (x = 10, y = 20)
Point p3 = new Point(10, 20, 30) // (x = 10, y = 20, z = 30)
No we can see in the code above that Kotlin generated overloads for the class constructor but someone of you may have doubt that why it created only 3 overloads? when there should be more than that like for x, y, z, (x, y), and so on...
The reason for that is to avoid ambiguity if there will be overloads for all then it will cause ambiguity like if we pass a single argument to the constructor it will not know which value is passed, is it x or y or z.
The overloads are generated from left to right because in Kotlin the default parameters are defined after the normal parameters.
JvmField
In Kotlin, properties are compiled with getters and setters it means if you want to operate on a property in Java you have to use getter/setter method for that property. @JvmField
allows you to expose a property as a public field in Java. lets learn with an example.
class Config {
var size = 100
}
Without Annotation
accessing Config
attributes
In Kotlin
Config.size
In Java
Config.getSize()
As we can see in above codes for both Kotlin and Java that we can access attribute size
normally but in Java we have to use getter for the property, The reason for this that by default all properties in Kotlin have backing field i.e. if no custom getter or setter are defined for an attribute Kotlin will generate default getters and setters. To use size
as a public field in Java we have to annotate it using JvmField
With Annotation
class Config {
`@JvmField` var size = 100
}
In Kotlin
Config.size
In Java
Config.size
Now we can see in above example we can access size as a public field.
With this article at OpenGenus.org, you must have the complete idea of JvmStatic, JvmOverloads and JvmFields Annotations in Kotlin.