What Is the Equivalent of Java Static Final Fields in Kotlin

What is the equivalent of Java static final fields in Kotlin?

According Kotlin documentation this is equivalent:

class Hello {
companion object {
const val MAX_LEN = 20
}
}

Usage:

fun main(srgs: Array<String>) {
println(Hello.MAX_LEN)
}

Also this is static final property (field with getter):

class Hello {
companion object {
@JvmStatic val MAX_LEN = 20
}
}

And finally this is static final field:

class Hello {
companion object {
@JvmField val MAX_LEN = 20
}
}

What is the equivalent of Java static methods in Kotlin?

You place the function in the "companion object".

So the java code like this:

class Foo {
public static int a() { return 1; }
}

will become

class Foo {
companion object {
fun a() : Int = 1
}
}

You can then use it from inside Kotlin code as

Foo.a();

But from within Java code, you would need to call it as

Foo.Companion.a();

(Which also works from within Kotlin.)

If you don't like having to specify the Companion bit you can either add a @JvmStatic annotation or name your companion class.

From the docs:

Companion Objects

An object declaration inside a class can be marked with the companion
keyword:

class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}

Members of the companion object can be called by using simply the class
name as the qualifier:

val instance = MyClass.create()

...

However, on the JVM you can have members of companion objects generated
as real static methods and fields, if you use the @JvmStatic
annotation. See the Java interoperability section for more details.

Adding the @JvmStatic annotation looks like this

class Foo {
companion object {
@JvmStatic
fun a() : Int = 1;
}
}

and then it will exist as a real Java static function, accessible from
both Java and Kotlin as Foo.a().

If it is just disliked for the Companion name, then you can also
provide an explicit name for the companion object looks like this:

class Foo {
companion object Blah {
fun a() : Int = 1;
}
}

which will let you call it from Kotlin in the same way, but
from java like Foo.Blah.a() (which will also work in Kotlin).

Static final field inheritance in kotlin

In Java, when the compiler sees B.AA, it automatically transforms it into A.AA. There's no real inheritance or overriding there.

Kotlin's developers decided not to emulate this feature, because it doesn't fit with thinking of static methods as belonging to an object: the companion object of B doesn't extend the companion object of A, and can't because you can't extend an object.

Note that similarly, in Java you can access the field via a.AA where a is an instance of A; you can't do that in Kotlin either.

Kotlin static methods and variables

Update: since this answer is getting a decent amount of upvotes, I really wanted to say that you shouldn't do the below, but instead just use object Foo { ... }, like Roman rightly points out in the comment.

Previous answer:

The closest thing to Java's static fields is a companion object. You can find the documentation reference for them here: https://kotlinlang.org/docs/reference/object-declarations.html#companion-objects

Your code in Kotlin would look something like this:

class Foo {

companion object {
lateinit var instance: Foo
}

init {
instance = this
}

}

If you want your fields/methods to be exposed as static to Java callers, you can apply the @JvmStatic annotation:

class Foo {

companion object {
@JvmStatic lateinit var instance: Foo
}

init {
instance = this
}

}

How do you make Kotlin static variables and functions for Java?

You can't. Well, at least in a pure Kotlin project.

Kotlin has no notion of static. The way static works in a Kotlin-Java project is by use of annotations on the Kotlin classes to tell the JVM that the desired variable/function should be exposed as a static to Java classes.

The following is an example guide for Kotlin-Java static interop (answer originally posted in What is the equivalent of Java static methods in Kotlin?):

Scenario 1: Creating a static method in Kotlin for Java

Kotlin

@file:JvmName("KotlinClass") //This provides a name for this file, so it's not defaulted as [KotlinClassKt] in Java
package com.frybits

class KotlinClass {
companion object {

//This annotation tells Java classes to treat this method as if it was a static to [KotlinClass]
@JvmStatic
fun foo(): Int = 1

//Without it, you would have to use [KotlinClass.Companion.bar()] to use this method.
fun bar(): Int = 2
}
}

Java

package com.frybits;

class JavaClass {

void someFunction() {
println(KotlinClass.foo()); //Prints "1"
println(KotlinClass.Companion.bar()); //Prints "2". This is the only way to use [bar()] in Java.
println(KotlinClass.Companion.foo()); //To show that [Companion] is still the holder of the function [foo()]
}

//Because I'm way to lazy to keep typing [System.out], but I still want this to be compilable.
void println(Object o) {
System.out.println(o);
}
}

This answer provides more depth than this, and should definitely be referenced for this scenario.


This next scenario handles creating static fields in Kotlin so that Java doesn't have to keep calling KotlinClass.foo() for those cases where you don't want a static function.

Scenario 2: Creating a static variable in Kotlin for Java

Kotlin

@file:JvmName("KotlinClass") //This provides a name for this file, so it's not defaulted as [KotlinClassKt] in Java
package com.frybits

class KotlinClass {

companion object {

//This annotation tells Kotlin to not generate the getter/setter functions in Java. Instead, this variable should be accessed directly
//Also, this is similar to [@JvmStatic], in which it tells Java to treat this as a static variable to [KotlinClass].
@JvmField
var foo: Int = 1

//If you want something akin to [final static], and the value is a primitive or a String, you can use the keyword [const] instead
//No annotation is needed to make this a field of [KotlinClass]. If the declaration is a non-primitive/non-String, use @JvmField instead
const val dog: Int = 1

//This will be treated as a member of the [Companion] object only. It generates the getter/setters for it.
var bar: Int = 2

//We can still use [@JvmStatic] for 'var' variables, but it generates getter/setters as functions of KotlinClass
//If we use 'val' instead, it only generates a getter function
@JvmStatic
var cat: Int = 9
}
}

Java

package com.frybits;

class JavaClass {

void someFunction() {
//Example using @JvmField
println(KotlinClass.foo); //Prints "1"
KotlinClass.foo = 3;

//Example using 'const val'
println(KotlinClass.dog); //Prints "1". Notice the lack of a getter function

//Example of not using either @JvmField, @JvmStatic, or 'const val'
println(KotlinClass.Companion.getBar()); //Prints "2"
KotlinClass.Companion.setBar(3); //The setter for [bar]

//Example of using @JvmStatic instead of @JvmField
println(KotlinClass.getCat());
KotlinClass.setCat(0);
}

void println(Object o) {
System.out.println(o);
}
}

One of the great features about Kotlin is that you can create top level functions and variables. This makes it greate to create "classless" lists of constant fields and functions, which in turn can be used as static functions/fields in Java.

Scenario 3: Accessing top level fields and functions in Kotlin from Java

Kotlin

//In this example, the file name is "KSample.kt". If this annotation wasn't provided, all functions and fields would have to accessed
//using the name [KSampleKt.foo()] to utilize them in Java. Make life easier for yourself, and name this something more simple
@file:JvmName("KotlinUtils")

package com.frybits

//This can be called from Java as [KotlinUtils.TAG]. This is a final static variable
const val TAG = "You're it!"

//Since this is a top level variable and not part of a companion object, there's no need to annotate this as "static" to access in Java.
//However, this can only be utilized using getter/setter functions
var foo = 1

//This lets us use direct access now
@JvmField
var bar = 2

//Since this is calculated at runtime, it can't be a constant, but it is still a final static variable. Can't use "const" here.
val GENERATED_VAL:Long = "123".toLong()

//Again, no need for @JvmStatic, since this is not part of a companion object
fun doSomethingAwesome() {
println("Everything is awesome!")
}

Java

package com.frybits;

class JavaClass {

void someFunction() {

println(KotlinUtils.TAG); //Example of printing [TAG]

//Example of not using @JvmField.
println(KotlinUtils.getFoo()); //Prints "1"
KotlinUtils.setFoo(3);

//Example using @JvmField
println(KotlinUtils.bar); //Prints "2". Notice the lack of a getter function
KotlinUtils.bar = 3;

//Since this is a top level variable, no need for annotations to use this
//But it looks awkward without the @JvmField
println(KotlinUtils.getGENERATED_VAL());

//This is how accessing a top level function looks like
KotlinUtils.doSomethingAwesome();
}

void println(Object o) {
System.out.println(o);
}
}

Another notable mention that can be used in Java as "static" fields are Kotlin object classes. These are zero parameter singleton classes that are instantiated lazily on first use. More information about them can be found here: https://kotlinlang.org/docs/reference/object-declarations.html#object-declarations

However, to access the singleton, a special INSTANCE object is created, which is just as cumbersome to deal with as Companion is. Here's how to use annotations to give it that clean static feel in Java:

Scenario 4: Using object classes

Kotlin

// There is no more need for the @file:JvmName() annotation. The object class below already handles the proper naming.

//This provides a name for this file, so it's not defaulted as [KotlinClassKt] in Java
package com.frybits

object KotlinClass { //No need for the 'class' keyword here.

//Direct access to this variable
const val foo: Int = 1

//Tells Java this can be accessed directly from [KotlinClass]
@JvmStatic
var cat: Int = 9

//Just a function that returns the class name
@JvmStatic
fun getCustomClassName(): String = this::class.java.simpleName + "boo!"

//Getter/Setter access to this variable, but isn't accessible directly from [KotlinClass]
var bar: Int = 2

fun someOtherFunction() = "What is 'INSTANCE'?"
}

Java

package com.frybits;

class JavaClass {

void someFunction() {
println(KotlinClass.foo); //Direct read of [foo] in [KotlinClass] singleton

println(KotlinClass.getCat()); //Getter of [cat]
KotlinClass.setCat(0); //Setter of [cat]

println(KotlinClass.getCustomClassName()); //Example of using a function of this 'object' class

println(KotlinClass.INSTANCE.getBar()); //This is what the singleton would look like without using annotations
KotlinClass.INSTANCE.setBar(23);

println(KotlinClass.INSTANCE.someOtherFunction()); //Accessing a function in the object class without using annotations
}

void println(Object o) {
System.out.println(o);
}
}

java static final in kotlin: Const 'val' initializer should be a constant value

In Kotlin, const keyword should only be used when value is compile time constant. In your case it is not(const val str = if (flag) "A" else "B"). You are using if condition to pass value to str on a condition that is not compile time constant.

So you just remove const keyword and it will work perfectly. Because val creates immutable variables same as final in Java. But there is a tradeoff, if const is removed. It will under the hood generates unnecessary object and getter for accessing that variable. To solve this issue use @JvmField annotation and you are good to go.

To read more go to Where Should I Keep My Constants in Kotlin?

Hope it helps.

Static final variable initialization (in Java) incorrect during Kotlin CI Tests

It's not multithreading, because the JVM prevents other threads from accessing a class while it is being initialized. This behavior is mandated by the Java Language Specification, section 12.4.2, step 2:

If the Class object for C indicates that initialization is in progress for C by some other thread, then release LC and block the current thread until informed that the in-progress initialization has completed, at which time repeat this step.

It is exceedingly unlikely for a JVM to have a bug in this area, since it would cause repeated initializer execution, which would be very noticeable.

However, a static final field can appear to have a changing value if:

  • there is a cyclic dependency among initializers

    Same section, step 3 writes:

    If the Class object for C indicates that initialization is in progress for C by the current thread, then this must be a recursive request for initialization. Release LC and complete normally.

    Therefore, a recursive initialization may allow a thread to read a static final field before it is assigned. This can only happen if class initializers create a cyclic dependency among initializers.

  • somebody (ab)uses reflection to reassign the static final field

  • the class is loaded by more than one class loader

    In this case, each class has its own copy of the static field, and may initialize it differently.

  • if the field is a compile time constant expression, and the code was compiled at different times

    The spec mandates that compile time constant expressions are inlined by the compiler. If different classes are compiled at different times, the value being inlined may have been different. (In your case, the expression is not compile time constant; I only mention this possiblity for the sake of future visitors).

From the evidence you have given, it is impossible to say which of these apply. That's why I recommend further investigation.



Related Topics



Leave a reply



Submit