Calling Kotlin from Java
Kotlin code can be easily called from Java. For example, instances of a Kotlin class can be seamlessly created and operated in Java methods. However, there are certain differences between Java and Kotlin that require attention when integrating Kotlin code into Java. On this page, we'll describe the ways to tailor the interop of your Kotlin code with its Java clients.
A Kotlin property is compiled to the following Java elements:
a getter method, with the name calculated by prepending the
a setter method, with the name calculated by prepending the
setprefix (only for
a private field, with the same name as the property name (only for properties with backing fields)
var firstName: String compiles to the following Java declarations:
If the name of the property starts with
is, a different name mapping rule is used: the name of the getter will be the same as the property name, and the name of the setter will be obtained by replacing
set. For example, for a property
isOpen, the getter will be called
isOpen() and the setter will be called
setOpen(). This rule applies for properties of any type, not just
All the functions and properties declared in a file
app.kt inside a package
org.example, including extension functions, are compiled into static methods of a Java class named
To set a custom name to the generated Java class, use the
Having multiple files with the same generated Java class name (the same package and the same name or the same
@JvmName annotation) is normally an error. However, the compiler can generate a single Java facade class which has the specified name and contains all the declarations from all the files which have that name. To enable the generation of such a facade, use the
@JvmMultifileClass annotation in all such files.
If you need to expose a Kotlin property as a field in Java, annotate it with the
@JvmField annotation. The field will have the same visibility as the underlying property. You can annotate a property with
@JvmField if it:
has a backing field
is not private
does not have
is not a delegated property
Late-Initialized properties are also exposed as fields. The visibility of the field will be the same as the visibility of
lateinit property setter.
Kotlin properties declared in a named object or a companion object will have static backing fields either in that named object or in the class containing the companion object.
Usually these fields are private but they can be exposed in one of the following ways:
Annotating such a property with
@JvmField makes it a static field with the same visibility as the property itself.
A late-initialized property in an object or a companion object has a static backing field with the same visibility as the property setter.
Properties declared as
const (in classes as well as at the top level) are turned into static fields in Java:
As mentioned above, Kotlin represents package-level functions as static methods. Kotlin can also generate static methods for functions defined in named objects or companion objects if you annotate those functions as
@JvmStatic. If you use this annotation, the compiler will generate both a static method in the enclosing class of the object and an instance method in the object itself. For example:
callStatic() is static in Java while
callNonStatic() is not:
Same for named objects:
Starting from Kotlin 1.3,
@JvmStatic applies to functions defined in companion objects of interfaces as well. Such functions compile to static methods in interfaces. Note that static method in interfaces were introduced in Java 1.8, so be sure to use the corresponding targets.
@JvmStatic annotation can also be applied on a property of an object or a companion object making its getter and setter methods static members in that object or the class containing the companion object.
Default methods in interfaces
Starting from JDK 1.8, interfaces in Java can contain default methods. To make all non-abstract members of Kotlin interfaces default for the Java classes implementing them, compile the Kotlin code with the
-Xjvm-default=all compiler option.
Here is an example of a Kotlin interface with a default method:
The default implementation is available for Java classes implementing the interface.
Implementations of the interface can override default methods.
Compatibility modes for default methods
If there are clients that use your Kotlin interfaces compiled without the
-Xjvm-default=all option, then they may be binary-incompatible with the code compiled with this option. To avoid breaking the compatibility with such clients, use the
-Xjvm-default=all mode and mark interfaces with the
@JvmDefaultWithCompatibility annotation. This allows you to add this annotation to all interfaces in the public API once, and you won't need to use any annotations for new non-public code.
Learn more about compatibility modes:
Default behavior. Do not generate JVM default methods and prohibit
@JvmDefault annotation usage.
Generate JVM default methods for all interface declarations with bodies in the module. Do not generate
DefaultImpls stubs for interface declarations with bodies, which are generated by default in the
If interface inherits a method with body from an interface compiled in the
disable mode and doesn't override it, then a
DefaultImpls stub will be generated for it.
Breaks binary compatibility if some client code relies on the presence of
In addition to the
all mode, generate compatibility stubs in the
DefaultImpls classes. Compatibility stubs could be useful for library and runtime authors to keep backward binary compatibility for existing clients compiled against previous library versions.
all-compatibility modes are changing the library ABI surface that clients will use after the recompilation of the library. In that sense, clients might be incompatible with previous library versions. This usually means that you need a proper library versioning, for example, major version increase in SemVer.
The compiler generates all the members of
DefaultImpls with the
@Deprecated annotation: you shouldn't use these members in Java code, because the compiler generates them only for compatibility purposes.
In case of inheritance from a Kotlin interface compiled in
DefaultImpls compatibility stubs will invoke the default method of the interface with standard JVM runtime resolution semantics.
Perform additional compatibility checks for classes inheriting generic interfaces where in some cases additional implicit method with specialized signatures was generated in the
disable mode: unlike in the
disable mode, the compiler will report an error if you don't override such method explicitly and don't annotate the class with
@JvmDefaultWithoutCompatibility (see this YouTrack issue for more details).
The Kotlin visibility modifiers map to Java in the following way:
privatemembers are compiled to
privatetop-level declarations are compiled to package-local declarations
protected(note that Java allows accessing protected members from other classes in the same package and Kotlin doesn't, so Java classes will have broader access to the code)
publicin Java. Members of
internalclasses go through name mangling, to make it harder to accidentally use them from Java and to allow overloading for members with the same signature that don't see each other according to Kotlin rules
Sometimes you need to call a Kotlin method with a parameter of type
KClass. There is no automatic conversion from
KClass, so you have to do it manually by invoking the equivalent of the
Class<T>.kotlin extension property:
Handling signature clashes with @JvmName
Sometimes we have a named function in Kotlin, for which we need a different JVM name in the bytecode. The most prominent example happens due to type erasure:
These two functions can not be defined side-by-side, because their JVM signatures are the same:
filterValid(Ljava/util/List;)Ljava/util/List;. If we really want them to have the same name in Kotlin, we can annotate one (or both) of them with
@JvmName and specify a different name as an argument:
From Kotlin they will be accessible by the same name
filterValid, but from Java it will be
The same trick applies when we need to have a property
x alongside with a function
To change the names of generated accessor methods for properties without explicitly implemented getters and setters, you can use
Normally, if you write a Kotlin function with default parameter values, it will be visible in Java only as a full signature, with all parameters present. If you wish to expose multiple overloads to Java callers, you can use the
The annotation also works for constructors, static methods, and so on. It can't be used on abstract methods, including methods defined in interfaces.
For every parameter with a default value, this will generate one additional overload, which has this parameter and all parameters to the right of it in the parameter list removed. In this example, the following will be generated:
Note that, as described in Secondary constructors, if a class has default values for all constructor parameters, a public constructor with no arguments will be generated for it. This works even if the
@JvmOverloads annotation is not specified.
Kotlin does not have checked exceptions. So, normally the Java signatures of Kotlin functions do not declare exceptions thrown. Thus, if you have a function in Kotlin like this:
And you want to call it from Java and catch the exception:
You get an error message from the Java compiler, because
writeToFile() does not declare
IOException. To work around this problem, use the
@Throws annotation in Kotlin:
When calling Kotlin functions from Java, nobody prevents us from passing
null as a non-nullable parameter. That's why Kotlin generates runtime checks for all public functions that expect non-nulls. This way we get a
NullPointerException in the Java code immediately.
When Kotlin classes make use of declaration-site variance, there are two options of how their usages are seen from the Java code. For example, imagine you have the following class and two functions that use it:
A naive way of translating these functions into Java would be this:
The problem is that in Kotlin you can write
unboxBase(boxDerived(Derived())) but in Java that would be impossible because in Java the class
Box is invariant in its parameter
T, and thus
Box<Derived> is not a subtype of
Box<Base>. To make this work in Java, you would have to define
unboxBase as follows:
This declaration uses Java's wildcards types (
? extends Base) to emulate declaration-site variance through use-site variance, because it is all Java has.
To make Kotlin APIs work in Java, the compiler generates
Box<? extends Super> for covariantly defined
Foo<? super Bar> for contravariantly defined
Foo) when it appears as a parameter. When it's a return value, wildcards are not generated, because otherwise Java clients will have to deal with them (and it's against the common Java coding style). Therefore, the functions from our example are actually translated as follows:
If you need wildcards where they are not generated by default, use the
In the opposite case, if you don't need wildcards where they are generated, use
Translation of type Nothing
Nothing is special, because it has no natural counterpart in Java. Indeed, every Java reference type, including
null as a value, and
Nothing doesn't accept even that. So, this type cannot be accurately represented in the Java world. This is why Kotlin generates a raw type where an argument of type
Nothing is used: