JVM上的Kotlin– Bytecode Generation

JVM上的Kotlin-它如何提供这么多功能?

介绍

到底是什么 “ JVM语言”,什么是Kotlin?不仅仅是Java意味着要在JVM上运行吗?
科特林 提供了许多Java无法提供的功能,例如适当的 功能类型, 扩展功能资料类别什至这是怎么可能的?我更深入地研究了Kotlin的工作原理以及“ JVM语言”的实际含义。我们将看看Kotlin的字节码生成。如果您也已经考虑过这些事情,那么本文应该为黑暗中带来些曙光

有关更详细的介绍 科特林的功能 你可以看看我的 入门指南.

Java虚拟机

快速简单的定义Java虚拟机 由计算机用来运行 Java字节码.
其实,关于这个复杂的工具,还有很多要学习的内容,有关详细信息,请参见 甲骨文的规格.

您可能已经知道JVM是在各种操作系统上运行的抽象虚拟计算机。实际上,JVM使Java具有“平台独立性”,因为JVM充当了执行的代码和OS之间的抽象。
就像任何真实的计算机一样,JVM提供了一个 一套 指示 可由程序使用,稍后由JVM本身转换为机器特定的指令。

如中所述 JVM规范,Java虚拟机 什么都不知道 关于 Java编程语言. However, it defines the binary format class which is a file containing machine 指示 (= 通过 tecodes) to be executed (beside some more information). This is a very interesting point, because it actually means, that

  1. JVM不仅专用于Java作为一种编程语言。
  2. you are free to choose a technology for creating JVM programs as long as you provide proper class files that are compliant to the very strict constraints.
  3. 无论使用哪种编程语言,任何Java字节码都可以与JVM上的其他Java字节码互操作。

创建类文件

从人类可读的源代码创建类文件的过程就是 编译器 做。一个示例是Oracle随Java附带的Java编译器 JDK (javac) that is capable of compiling .java files to .class files.
除了Java,还有许多其他功能 JVM语言 在过去的几年中已经出现了这种方法,所有这些方法都试图为开发人员提供替代的抽象方法,以便为JVM创建程序。
这些语言之一是 科特林.

科特林字节码生成-什么是Kotlin?

如官方所说 常见问题,“ 科特林产生Java兼容字节码”,这意味着Kotlin编译器能够将所有不错的功能转换为JVM兼容指令,甚至可以使用 IntelliJ IDEA 工具。
让我们看一些示例:

顶级功能

科特林
//File.kt
fun foobar(){}

可以使用IntelliJ研究在.kt文件中定义的此简单顶级功能:
“工具– 科特林 –显示Kotlin字节码” 将在IDE内打开一个新窗口,提供编译器将为当前编辑的Java字节码进行实时预览。 .kt文件.

Java字节码
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
}

恐怕只有很少的人可以实际读取这些文件,这就是为什么我们也可以选择“反编译”选项的原因。然后,我们将向您提供一个Java类,其中包含了先前用Kotlin描述的功能:

顶级函数反编译
public final class FileKt {
   public static final void foobar() {
   }
}

如您所见并且可能已经知道,Kotlin顶层类被编译为带有静态函数的最终Java类。 [1]。让我们来看一个更困难的:

类和扩展功能

科特林
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.
首先,我们应该看一下将类编译成什么,这很有趣,因为我们使用了 主要建设者val关键字 这里。

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 科特林 🙂

扩展功能反编译
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();
   }
}

扩展函数本身通过它的编译为静态方法 接收对象 作为Java代码中的参数。
One thing we can also observe in the example is the use of a class called Intrinsics. This one is part of the 科特林 标准库 和 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? 和 of course access length in a safe way.

具有可空参数的扩展功能反编译
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 编译器 that null is an acceptable thing to point to.
下一个示例有些棘手。它是Kotlin和Java代码之间最大的区别:

范围
科特林
fun loopWithRange(){
    for(i in 5 downTo 1 step 2){
        print(i)
    }
}
反编译
 public static final void loopWithRange() {
      IntProgression var10000 = 范围Kt.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 downTostep are 中缀符号,实际上是函数调用。为了提供这种灵活性,似乎只需要多一点代码即可。

你怎么看?尽管Kotlin代码非常出色,但看起来并不那么好,对吗?

结论

I think, most of the time you don’t really care 关于 what the 科特林 编译器 produces behind the scenes. Yet, I find observing it really interesting 和 helpful as it supports answering my initial questions in some way. It provides an answer to "What is 科特林" in a way 😉 Of course, 科特林 is much more than just abstracting Java’s operators since it also provides so many extensions to existing Java classes like List or String.
尽管如此,我们还看到有时编译的Java代码比必须的更为冗长。这会影响性能吗?是的,确实的,它的影响很小。看看这个 介绍 通过 德米特里·杰梅罗夫(Dmitry Jemerov) 如果您对更多考虑性能的“ 科特林 – Java字节码”示例感兴趣,

最后,如果您想了解Kotlin的美丽功能,我推荐这本书 行动中的科特林 给你!

让我知道您对此有何想法,如果您愿意,请保持联系!


 1。这种结构看起来像扩展功能的含义:实用程序类

3个想法“JVM上的Kotlin– Bytecode Generation

发表评论

您的电子邮件地址不会被公开。 必需的地方已做标记 *