In Java you cannot extend a final class, but in Kotlin you can write extension method to such final classes. How did they make it work internally? I couldn't find any article that explained the inner workings of Kotlin Extension Methods.
2 Answers
In Java you cannot extend a final class, but in Kotlin you can write extension method to such final classes
I think you are assuming extension methods used inheritance which is not. It is rather a static method disguised in kotlin syntactic sugar. For example look at the below simple extension method:
String.removeSpace(): String {
return this.replace(" ", "")
}
You can think it as equivalent to the following java code.
static String removeSpace(String input) {
return input.replace(" ", "")
}
What kotlin does here is it provides wrapper on top so that by using this
you can get the instance of the caller. By combining that with Kotlin's capability of define function as first class citizen, you can write elegant thing like this:
fun String.removeSpace() = this.replace(" ", "")
If you wonder how Kotlin code covert into Java code, there is a way to look at it. IntelliJ provides decompile Kotlin byte code to Java code. You can find it Tools -> Kotlin -> Show Kotlin Bytecode
and hit the Decompile
. Then it will show Java code.
Here is an example.
Kotlin
val Int.asByteArray get() =
byteArrayOf(
(this shr 24).toByte(),
(this shr 16).toByte(),
(this shr 8).toByte(),
this.toByte())
val Int.asHex get() = this.asByteArray.asHexUpper
@ExperimentalUnsignedTypes
val ByteArray.asInt get() =
((this[0].toUInt() and 0xFFu) shl 24) or
((this[1].toUInt() and 0xFFu) shl 16) or
((this[2].toUInt() and 0xFFu) shl 8) or
(this[3].toUInt() and 0xFFu)
Java
public final class IntExtensionKt {
@NotNull
public static final byte[] getAsByteArray(int $this$asByteArray) {
return new byte[]{(byte)($this$asByteArray >> 24), (byte)($this$asByteArray >> 16), (byte)($this$asByteArray >> 8), (byte)$this$asByteArray};
}
@NotNull
public static final String getAsHex(int $this$asHex) {
return HexExtensionKt.getAsHexUpper(getAsByteArray($this$asHex));
}
/** @deprecated */
// $FF: synthetic method
@ExperimentalUnsignedTypes
public static void asInt$annotations(byte[] var0) {
}
public static final int getAsInt(@NotNull byte[] $this$asInt) {
Intrinsics.checkParameterIsNotNull($this$asInt, "$this$asInt");
byte var1 = $this$asInt[0];
boolean var2 = false;
int var5 = UInt.constructor-impl(var1);
short var6 = 255;
boolean var3 = false;
var5 = UInt.constructor-impl(var5 & var6);
byte var7 = 24;
var3 = false;
var5 = UInt.constructor-impl(var5 << var7);
byte var8 = $this$asInt[1];
var3 = false;
int var9 = UInt.constructor-impl(var8);
short var10 = 255;
boolean var4 = false;
var9 = UInt.constructor-impl(var9 & var10);
byte var11 = 16;
var4 = false;
var9 = UInt.constructor-impl(var9 << var11);
var3 = false;
var5 = UInt.constructor-impl(var5 | var9);
var8 = $this$asInt[2];
var3 = false;
var9 = UInt.constructor-impl(var8);
var10 = 255;
var4 = false;
var9 = UInt.constructor-impl(var9 & var10);
var11 = 8;
var4 = false;
var9 = UInt.constructor-impl(var9 << var11);
var3 = false;
var5 = UInt.constructor-impl(var5 | var9);
var8 = $this$asInt[3];
var3 = false;
var9 = UInt.constructor-impl(var8);
var10 = 255;
var4 = false;
var9 = UInt.constructor-impl(var9 & var10);
var3 = false;
return UInt.constructor-impl(var5 | var9);
}
}
As you can see, a Kotlin extension method became public final static
method in final class
in Java.