Calling Java code from Kotlin
In this section we describe some details about calling Java code from Kotlin. In most cases, you just use it:
If a Java method returns void, it will return
Unit when called from Kotlin. If, by any chance, someone uses that return value, it will be assigned at the call site by the Kotlin compiler, since the value itself is known in advance (being
Escaping for Java identifiers that are keywords in Kotlin
Some of the Kotlin keywords are valid identifiers in Java: in, object, is, etc. It may happen that some of your favorite Java libraries use these words as names for methods. In this situation you still can call those methods from Kotlin, but you need to escape their names with backticks:
Any reference in Java may be
null. So, all the Java methods called from Kotlin return nullable references (except for those annotated with
@NotNull). This allows Kotlin to keep the guarantee of having no
NullPointerExceptions unless they are explicitly thrown by Kotlin code or caused by something inside Java code called from Kotlin.
Consider the following examples:
In Kotlin, all exceptions are unchecked, meaning that the compiler does not force you to catch any of them. So, when you call a Java method that declares a checked exception, Kotlin does not force you to do anything:
Java generics in Kotlin
- Java's wildcards are converted into type projections
Foo<? extends Bar>becomes
Foo<? super Bar>becomes
- Java's raw types are converted into star projections
Like Java's, Kotlin's generics are not retained at runtime, i.e. objects do not carry information about actual type arguments passed to their constructors, i.e.
ArrayList<Integer>() is indistinguishable from
ArrayList<Character>(). This makes it impossible to perform is-checks that take generics into account. Kotlin only allows is-checks for star-projected generic types:
Arrays in Kotlin are invariant, unlike Java. This means that Kotlin does not let us assign an
Array<String> to an
Array<Any>, which prevents a possible runtime failure. Neither does it allow us to pass an array of a subclass as an array of superclass to a Java method. In most cases, this should not be a major obstacle, but if one really needs to pass an array in a covariant way, they may cast explicitly.
On the Java platform, having a generic class
Array to represent arrays leads to a lot of boxing/unboxing operations. As arrays are mostly use where performance is critical, we introduced a workaround for this issue and defined classes
CharArray and so on, which are not related to the Array class and are compiled down to Java's primitive arrays.
When Java types are imported into Kotlin, all the references of type
java.lang.Object are turned into
Any?, for any reference may be used there.
The difference between
Any is that
Any declares fewer functions than
java.lang.Object. This is done for elegance and platform-independence. So, all that
Any has is
From the programmer's perspective almost nothing changes compared to Java: all the existing toString() implementations work, and when you need a custom
toString() for your class, you simply override it:
== stands for a guarded call to
equals(). The expression on the left-hand side must have a method named
equals that takes one parameter of type
Any? and returns
Boolean. Thus, all the Java objects have it out of the box. Like
equals() can be overridden in Kotlin classes and there's an extension function that works on nullable references.
hashCode() has no special operator convention and no support for nullable references (there's no universal default semantics for it).
Effective Java Item 69 kindly suggests to Prefer concurrency utilities to wait and notify. Thus, these methods are not available on references of type
Any, only on Java objects.
To retrieve the type information from an object, one uses the
javaClass extension property.
Instead of Java's
Any does not declare a
finalize() function, so when you really need to override it, this is done "by convention":
Note that there's no override keyword before the function. For JVM this will work as an override, because method signature matches, but for Kotlin there's no override.
clone() can be overridden by with specifying
Cloneable as a supertype:
Do not forget about Effective Java Item 11: Override clone judiciously.
Inheritance from Java classes
At most one Java-class (and as many Java interfaces as you like) can be a supertype for a class in Kotlin. This class must go first in the supertype list.
Accessing static members
Static members of Java classes form "class objects" for these classes. One cannot pass such a "class object" around as a value, but can access the members explicitly, for example
Calling Kotlin code from Java
We plan to target more platforms in the future, but currently, Kotlin is only compiled for the Java platform. This means that the compiler generates Java bytecode, and thus the code that we write in Kotlin can be called from Java. There are some concepts in Kotlin that are not available in Java, though. In this section, we briefly describe how these concepts are mapped to Java concepts.
All the functions and properties declared inside a package
org.foo.bar are put into a Java class named
For the root package (the one that's called a "default package" in Java), a class named
_DefaultPackage is created.
As we mentioned above, Kotlin does not have checked exceptions. So, normally, the Java signatures of Kotlin functions do not declare exceptions thrown. Thus, if we have a function in Kotlin like this:
And we want to call it from Java and catch the exception:
we get an error message from the Java compiler, because
foo() does not declare
To work around this problem, use the
When calling Kotlin functions from Java, nobody prevents us from passing a
null as a non-null 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.
Property getters are turned into
get-methods, and setters – into