As stated in the official FAQs, "Kotlin produces Java compatible bytecode", which means that the Kotlin compiler is capable of transforming all the nice features into JVM compatible instructions and this can even be observed using IntelliJ IDEA tools.

Let’s look at some examples: Top Level Functions

Kotlin //File.kt fun foobar(){}

This simple top-level function defined in a .kt file can be investigated with IntelliJ:

"Tools → Kotlin → Show Kotlin Bytecode" will open a new window inside the IDE providing a live preview of the Java bytecode the compiler would create for the currently edited .kt file.

Java bytecode public final class de/swirtz/kotlin/FileKt { // access flags 0x19 public final static foobar()V L0 LINENUMBER 3 L0 RETURN L1 MAXSTACK = 0 MAXLOCALS = 0 @Lkotlin/Metadata; // compiled from: File.kt }

I’m afraid only a few people can actually read these files, which is why we can also choose the option "Decompile". Afterwards we’ll be presented a Java class enclosing the functionality previously described with Kotlin:

Top Level Function decompiled public final class FileKt { public static final void foobar() { } }

As you can see and probably already know, a Kotlin top level class is compiled into a final Java class with a static function . Let’s see a more difficult one: Classes and Extension Functions

Kotlin class MyClass(val i: Int) fun MyClass.myExtension(value: String) = value.length

This one shows a simple class MyClass with a property of type Int , as well as a top level extension function.

First, we should have a look at what the class is compiled to, which is quite interesting as we used a primary constructor and the val keyword here.

Class in Java public final class MyClass { private final int i; public final int getI() { return this.i; } public MyClass(int i) { this.i = i; } }

As we would expect: the property is a final member being assigned in the single constructor. Yet, so much simpler in Kotlin 🙂

Extension Function decompiled public final class FileKt { public static final int myExtension(@NotNull MyClass $receiver, @NotNull String value) { Intrinsics.checkParameterIsNotNull($receiver, "$receiver"); Intrinsics.checkParameterIsNotNull(value, "value"); return value.length(); } }

The extension function itself is compiled to a static method with its receiver object as a parameter in the Java code.

One thing we can also observe in the example is the use of a class called Intrinsics . This one is part of the Kotlin stdlib and is utilized because the parameters are required to be not null .

Let’s see what would happen if we changed the inital extension function’s parameter to value: String? and of course access length in a safe way.

Extension Function with nullable Parameter decompiled public final class FileKt { @Nullable public static final Integer myExtension(@NotNull MyClass $receiver, @Nullable String value) { Intrinsics.checkParameterIsNotNull($receiver, "$receiver"); return value != null?Integer.valueOf(value.length()):null; } }

Checking value is not necessary anymore since we told the compiler that null is an acceptable thing to point to.

The next example is a bit more tricky. It’s the one with the greatest difference between Kotlin and Java code:

Ranges Kotlin fun loopWithRange(){ for(i in 5 downTo 1 step 2){ print(i) } }

decompiled public static final void loopWithRange() { IntProgression var10000 = RangesKt.step(RangesKt.downTo(5, 1), 2); int i = var10000.getFirst(); //i: 5 int var1 = var10000.getLast(); //var1: 1 int var2 = var10000.getStep(); //var2: -2 if(var2 > 0) { if(i > var1) { return; } } else if(i < var1) { return; } while(true) { System.out.print(i); if(i == var1) { return; } i += var2; } }

Although the Java code still is quite comprehensible, probably nobody would write it in real life, because a simple for could do it, too. We need to consider that downTo and step are infix notations, which are function calls actually. In order to provide this flexibility, a little more code just seems to be necessary.