I'm trying to convert the following code to Kotlin AND still have one of the classes (Foo) used by Java. What is the proper way of making this conversion?
Original Java:
public class Foo { public static final String C_ID = "ID"; public static final String C_NAME = "NAME"; public static final String[] VALUES = {"X", "Y", "Z"}; public static String[] getAll() { return new String[] {C_ID, C_NAME}; } } public class Bar { public void doStuff() { String var1 = Foo.C_ID; String[] array1 = Foo.VALUES; String[] array2 = Foo.getAll(); } }
Auto conversion fo Foo to Kotlin
object Foo { val C_ID = "ID" val C_NAME = "NAME" val VALUES = arrayOf("X", "Y", "Z") val all: Array<String> get() = arrayOf(C_ID, C_NAME) }
Problem:
Bar class can no longer access C_ID or VALUES (error: "private access")
if I put "const" in front of C_ID, it works... but I cannot do the same with VALUES ("const" can ONLY be used on primatives or String)
Is there a different way I should be doing this (so both Java code and Kotlin code can access everything in Foo)?
By using @JvmStatic annotation Adding @JvmStatic annotation simply before the members to be declared as the equivalent of static ones in Java works well in Kotlin to provide the same functionality.
In Kotlin, we can achieve the functionality of a static method by using a companion identifier. For example, If you want to create a method that will return the address of your company then it is good to make this method static because for every object you create, the address is going to be the same.
In Kotlin, you have the const keyword that's equal to the static keyword in Java. The const keyword is used to create a variable that's known to Kotlin before the compilation, so you don't need to create an instance of a class to use it.
Kotlin doesn't support static keyword. It means that you can't create a static method and static variable in Kotlin class.
The current semantics come from Kotlin Beta Candidate:
@JvmField and objects
We have made the strategy for generating pure fields (as opposed to
get
/set
pairs) more predictable: from now on only properties annotated as@JvmField
,lateinit
orconst
are exposed as fields to Java clients. Older versions used heuristics and created static fields in objects unconditionally, which is against our initial design goal of having binary-compatibility-friendly APIs by default.Also, singleton instances are now accessible by the name
INSTANCE
(instead ofINSTANCE$
).
According to this and to the reference, there are three ways of working with properties of a Kotlin object
from Java:
Use Foo.INSTANCE
.
By default, properties of object
won't be static fields for Java, but Java can access the properties through Foo
object instance -- Foo.INSTANCE
.
So the expression will be Foo.INSTANCE.getC_ID()
.
Mark a property with @JvmStatic
annotation:
object Foo { @JvmStatic val C_ID = "ID" //... }
This will generate static getter for C_ID
instead of Foo
instance getter which will be accessible as Foo.getC_ID()
.
Use @JvmField
annotation on property declaration:
object Foo { @JvmField val C_ID = "ID" //... }
This will make Kotlin compiler generate a static field for Java instead of property. Then in Java you can access it as a static field: Foo.C_ID
.
But it won't work on properties without backing fields like all
in your example.
For primitives, as you stated, one can use const
which will have the same effect as @JvmField
in terms of visibility in Java.
By the way, when it comes to methods, the situation is the same, and there is @JvmStatic
annotation for them.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With