扩展方法在 Kotlin 中如何工作?

How does a extension method work in Kotlin?

在 Java 中你不能扩展一个最终的 class,但是在 Kotlin 中你可以为这样的最终 class 编写扩展方法。他们是如何让它在内部发挥作用的?我找不到任何解释 Kotlin 扩展方法内部工作原理的文章。

In Java you cannot extend a final class, but in Kotlin you can write extension method to such final classes

我认为您假设扩展方法使用了继承,但事实并非如此。它是一种伪装在 kotlin 语法糖中的静态方法。例如看下面的简单扩展方法:

String.removeSpace(): String {
    return this.replace(" ", "")
}

你可以认为它等同于下面的java代码。

static String removeSpace(String input) {
    return input.replace(" ", "")
}

kotlin 在这里做的是它在顶部提供包装器,以便通过使用 this 您可以获得调用者的实例。通过将其与 Kotlin 将函数定义为第一个 class 公民的功能相结合,您可以编写如下优雅的内容:

fun String.removeSpace() = this.replace(" ", "")

如果您想知道 Kotlin 代码是如何转换成 Java 代码的,有一种方法可以查看。 IntelliJ 提供将 Kotlin 字节码反编译为 Java 代码。您可以找到它 Tools -> Kotlin -> Show Kotlin Bytecode 并点击 Decompile。然后它将显示 Java 代码。

这是一个例子。

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);
   }
}

如您所见,Kotlin 扩展方法在 Java 中变成了 public final static 中的方法 final class