@JvmStatic, @JvmOverloads and @JvmField in Kotlin

Are you an Android developer? If yes, then which language do you prefer to write code for your Android application? Is it Java or Kotlin? Did I ask the wrong question? So, when it comes to Android app development, we have two communities, one is the Java and the other is Kotlin. Java people say that Java is the perfect language for Android development because both Java and Kotlin are JVM dependent. While the Kotlin people say that Kotlin is best because you can write the same in a much precise way having a lesser number of lines of code (there are other benefits too). Here, is a quick comparison between the two(no offense Java people :))

So, don’t worry, we are not here to tell which language is better for Android development. But we will learn how both communities(Java and Kotlin) can work together. Yeah, you heard it right. You can use Kotlin code in your Java code. So, if you have migrated to Kotlin from Java then you can use your existing Java projects and make changes by using the Kotlin language. Another benefit of this interoperability is that if you are using Kotlin and at some time you are finding it difficult to implement something using Kotlin then you can implement the same using Java also.

So, let’s see how can we achieve this.

@JvmStatic

In Kotlin, the package-level functions are represented as static methods. Also, in Kotlin, you can make static methods for functions that are defined in some companion object or named object by using the @JvmStatic annotation. For example:

class ClassName {
    companion object {
        @JvmStatic fun iAmStaticMethod() {
            //body of Static function
        }
        fun iAmNonStaticMethod() {
            //body of Non static function
        }
    }
}

Here, iAmStaicMethod() is a static function and iAmNonStaticMethod() is a non-static function.

So, to call the above methods in Java, write the below code:

ClassName.iAmStaticMethod(); // works fine
ClassName.iAmNonStaticMethod(); // error: not a static method
ClassName.Companion.iAmStaticMethod(); // instance method remains
ClassName.Companion.iAmNonStaticMethod(); // the only way it works

For named objects, same procedure can be followed:

object ObjectName {
    @JvmStatic fun iAmStaticMethod() {
        //body of Static function
    }
    fun iAmNonStaticMethod(){
        //body of Non static function
    }
}

So, to call the above methods in Java, write the below code:

ObjectName.iAmStaticMethod(); // works fine
ObjectName.iAmNonStaticMethod(); // error
ObjectName.INSTANCE.iAmStaticMethod(); // works, a call through the singleton instance
ObjectName.INSTANCE.iAmNonStaticMethod(); // works too

@JvmOverloads

Let’s create a class with some variables, few of them are initialized and few of them are not initialized. So, we are creating one Event class and we will be having two properties i.e. event name and event date. By default we will take the date of the event to be the current date if you are not passing the date while making an object of the class. Following is the code for the same:

data class Event( val name: String, val date: Date = Date())

Here, in the above code, by default, the current date will be taken if you are not passing the date in the parameter. So, if we are calling from Kotlin, the following code will run with no error:

val eventOne = Event("MindOrks")
val eventTwo = Event("MindOrks", Date())

But if we are calling the same from the Java then you have to pass all the parameters otherwise you will get some error:

Event eventOne = new Event("MindOrks");//Here we are passing only one argument so we will encounter error
Event eventTwo = new Event("MindOrks", new Date());//No error

We have pass both the parameters. So, what's the use of default value if we have to pass both values.

So, to use the default value, we can use the @JvmOverloads annotation. Now, after using the annotation, the Kotlin code will be:

data class Event @JvmOverloads constructor( val name: String, val date: Date = Date())

Here, we have used the @JvmOverloads annotation. Now, calling from Java, you need not pass all the parameters:

Event eventOne = new Event("MindOrks"); //No error
Event eventTwo = new Event("MindOrks", new Date()); //No error

@JvmField

Let's take the same example of the Event class that we saw in the above part of the blog. If we are writing the same code in Java then we must have to include some getters and setters for the properties of the class. For example, for the name of the event we have to make a getter method:

public class Event {
    public final String event;

    public getName(String event) {
        this.event = event;
    }
}

And the Kotlin code for the same will be:

data class Event ( val name: String, val date: Date = Date())

So, if we are accessing the properties of the class then the code in Kotlin is:

val event = Event("MindOrks", Date())
val name = event.name

But in Java, you have to use the getter method:

Event event = new Event("MindOrks", new Date());
String name = event.getName();

So, if you want a particular field to be used as normal field and not as getter or setter then you have to tell the compiler not to generate any getter and setter for the same and this can be done by using the @JvmField annotation. So, the Kotlin code after using the @JvmField annotation will be:

data class Event (@JvmField val name: String, val date: Date = Date())

Now, in Java also, you can access the fields of the class in the same way as in Kotlin:

Event event = new Event("MindOrks", new Date());
String name = event.name;

That’s all for this blog. Hope after reading this blog, both the Java supporters and the Kotlin supporters are now friends and they must be looking to build some cool application by using Java and Kotlin in the same app :)

To learn more about Android, you can visit our blogging website.

Keep Learning :)

Team MindOrks!