Kotlin doesn't have a static keyword, so what should you do if you want your code to be written in Kotlin, but still adhere to patterns and conventions that require static, or at least the appearance of static? There are a few different options for these cases.
One of the more common uses of static methods and fields is for things such as helper functions and constants. In Java, it's common to have classes that exist for the sole purpose of containing static methods or fields. In Kotlin, these types of static methods/fields, and their associated classes, can be replaced with things such as top-level functions and properties, extension functions, or companion objects. We'll look at these in depth later in the chapter.
The Kotlin alternatives don't always translate to the same bytecode as their static Java counterparts. If you need true JVM static properties or methods, you can leverage the @JVMStatic annotation. Let's explore this annotation with an example.
Here, we've defined a Foo class with a companion object that contains a single const val property:
class Foo {
companion object {
const val ID = "123"
}
}
From Java, we can access the const property directly, like this:
String id = Foo.ID;
If we wanted to enforce the rule that the value should be accessed through a static getter, we could use the @JVMStatic annotation like this:
class Foo {
companion object {
@JvmStatic
val ID = "123"
}
}
By doing so, it would then force us to access the property using the generated getter:
String id = Foo.getID();
This annotation will force the compiler to generate static methods and/or getters/setters for the annotated target. By using this annotation, you can instruct the API to behave similarly with Java.
In this section, we've seen several examples of how to work with Kotlin from Java and some of the limitations that includes. In the next section, we'll explore how to work with Java code from Kotlin.