1. Overview

In this quick tutorial, we’ll discuss static final variables in Java and learn about their equivalent in Kotlin.

In Java, declaring static final variables helps us create constants. And in Kotlin, we have several ways to achieve the same goal.

2. Inside an object

Firstly, let’s take a look at declaring constants in a Kotlin object:

object TestKotlinConstantObject {
    const val COMPILE_TIME_CONST = 10

    val RUN_TIME_CONST: Int
    init {
        RUN_TIME_CONST = TestKotlinConstantObject.COMPILE_TIME_CONST + 20;
    }
}

In the above example, we use const val to declare a compile-time constant, and val to declare a run-time constant.

We call them in our Kotlin code in the same way as Java static final variables:

// Kotlin
assertEquals(10, TestKotlinConstantObject.COMPILE_TIME_CONST)
assertEquals(30, TestKotlinConstantObject.RUN_TIME_CONST)

Note, though, that we cannot use TestKotlinConstantObject.RUN_TIME_CONST in Java code. The val keyword by itself, without the const keyword, doesn’t expose Kotlin fields as public for Java classes to call.

To use the RUN_TIME_CONST constant in our Java code, we should access it through TestKotlinConstantObject.INSTANCE.getRun_TIME_CONST():

// Java
assertEquals(10, TestKotlinConstantObject.COMPILE_TIME_CONST);
assertEquals(30, TestKotlinConstantObject.INSTANCE.getRUN_TIME_CONST());

Alternatively, we can use @JvmField to expose val variables to create Java-friendly static final variables:

@JvmField val JAVA_STATIC_FINAL_FIELD = 20

We can call this one just like a const val variable in both Kotlin and Java classes:

// Kotlin
assertEquals(20, TestKotlinConstantObject.JAVA_STATIC_FINAL_FIELD)

and

// Java
assertEquals(20, TestKotlinConstantObject.JAVA_STATIC_FINAL_FIELD);

In addition, we also have @JvmStatic, which we can use in a similar manner to @JvmField. But we’re not using it here since @JvmStatic makes the property accessor static in Java but not the variable itself.

3. Inside a Kotlin class

The declaration of these constants is similar in a Kotlin class, but it’s done inside its companion object:

class TestKotlinConstantClass { 
    companion object { 
        const val COMPANION_OBJECT_NUMBER = 40 
    } 
}

And we can do the same as before:

// Kotlin
assertEquals(40, TestKotlinConstantClass.COMPANION_OBJECT_NUMBER)

and

// Java
assertEquals(40, TestKotlinConstantClass.COMPANION_OBJECT_NUMBER);

4. Inside a kt File

Apart from declaring static variables in a Kotlin object and a companion object, we can also declare them at the top level of a Kotlin file (*.kt).

Let’s see an example:

//KotlinFile.kt

package com.baeldung.constant

const val VALUE_IN_KT_FILE = 42
val greeting="Hello"

As the example shows, we’ve created KotlinFile.kt. In this file, we don’t have any classes, but we’ve declared two variables at the top level of the file.

Then, in Kotlin, we can directly use them in code:

// Kotlin
assertEquals(42, VALUE_IN_KT_FILE)
assertEquals("Hello", greeting)

However, we cannot directly access these variables in Java. First, we cannot access a variable without a class or an object in Java. The compiler will compile the Filename.kt file to a class with the name FilenameKt. There are a few rules for special cases in the filename:

  • The first letter is converted to uppercase: myKotlin.kt -> MyKotlinKt
  • Add a leading underscore (“*_*“) if the first character isn’t valid for the Java class name: 7myKotlin.kt ->_7myKotlinKt
  • Replace periods (“.”) in the filename with underscores (“_”): my.Kotlin.kt -> My_KotlinKt

In our case, the filename is KotlinFile.kt. So, we can access the variables through the class “KotlinFileKt“:

assertEquals(42, KotlinFileKt.VALUE_IN_KT_FILE);
assertEquals("Hello", KotlinFileKt.getGreeting());

As the code shows, similar to accessing variables declared in the Kotlin object in Java, if it’s a const variable, we can access it directly. However, if it’s a regular val variable, we need to get its value through the getter method. Similarly, we can add the @JvmField annotation to make this variable a static final variable in Java. We’ll see this in another example later.

As we can see, declaring variables in a kt file is pretty easy. However, getting the compiled class name isn’t so straightforward. To make this easier, we can use the @file:JvmName annotation to define the compiled class name.

Next, let’s create the KotlinFileWithAnnotation.kt file with the @file:JvmName(“NiceKotlinUtil”) annotation and annotate a regular val variable with @JvmField:

// KotlinFileWithAnnotation.kt

@file:JvmName("NiceKotlinUtil")

package com.baeldung.constant

const val VALUE_IN_KT_FILE_WITH_ANNOTATION = 4242
@JvmField val greetingFromFileWithAnnotation = "Hello world"

Now, we can access the static variables via the NiceKotlinUtil class:

// Java
assertEquals(4242, NiceKotlinUtil.VALUE_IN_KT_FILE_WITH_ANNOTATION);
assertEquals("Hello world", NiceKotlinUtil.greetingFromFileWithAnnotation);

5. Conclusion

In this article, we’ve gone through the usage of const, val, @JvmField, and file:@JvmName in Kotlin to create static final variables.

As always, the code can be found over on GitHub.