为什么 kotlin 中的 getter 使用 INVOKEVIRTUAL?

问题描述 投票:0回答:1

所以我在 kotlin 中有一个简单的类和一个从该类获取字段的函数:

class SomeClass {
    var value = 1
}

fun showValue() {
    val klass = SomeClass()
    println(klass.value)
}

函数字节码如下所示:

public final static showValue()V
   L0
    LINENUMBER 8 L0
    NEW com/korol/kittybot/SomeClass
    DUP
    INVOKESPECIAL com/korol/kittybot/SomeClass.<init> ()V
    ASTORE 0
   L1
    LINENUMBER 9 L1
    ALOAD 0
    INVOKEVIRTUAL com/korol/kittybot/SomeClass.getValue ()I
    ISTORE 1
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    ILOAD 1
    INVOKEVIRTUAL java/io/PrintStream.println (I)V
   L2
    LINENUMBER 10 L2
    RETURN
   L3
    LOCALVARIABLE klass Lcom/korol/kittybot/SomeClass; L1 L3 0
    MAXSTACK = 2
    MAXLOCALS = 2

由于某种原因,getter 不是静态的。

INVOKEVIRTUAL com/korol/kittybot/SomeClass.getValue
。我很感兴趣为什么。据我了解,虚拟调用适用于具有多种实现的函数。但这里的领域不是开放的,类既不是抽象的,也不是开放的。如果有人能解释一下,我将不胜感激。

Kotlin 通常不会在类中生成静态。它只能在同伴或物体中生成。

kotlin jvm bytecode
1个回答
0
投票

首先我要说的是,我不是 Kotlin 程序员。

由于某种原因,getter 不是静态的。

getter 不是静态的,因为您获取的属性不是静态的。 它是(用 Java 术语来说)

final
,但是
static
final
是不同的东西。

(方法)的区别是:

  • 'static' 表示该方法没有目标对象
  • ‘final’表示该方法不能被重写

对于您的 getter 示例:

  • 有一个目标对象:要访问其
    SomeClass
    value
    实例,因此 getter cannot
    static
    (在 Java 意义上)。
  • getter 可能是
    final
    (在 Java 意义上),因为
    SomeClass
    不是
    open
    (在 Kotlin 意义上)。

那么 JVM 字节码呢?

  • INVOKESTATIC
    用于调用
    static
    方法。 它不允许有目标对象。
  • INVOKEVIRTUAL
    用于调用常规非静态方法。 它期望操作栈上的目标对象。
  • INVOKEINTERFACE
    用于调用接口而不是子类层次结构中定义的非静态方法。
  • INVOKESPECIAL
    适用于特殊情况:构造函数、类初始化,但可以用于调用
    final
    方法,前提是该方法可以在编译时绑定。
  • INVOKEDYNAMIC
    适用于需要更灵活(运行时)调度方法调用的(其他)特殊情况。

在您的示例中,Kotlin 编译器可以发出

INVOKEVIRTUAL
INVOKESPECIAL
字节码来调用 getter。 两者都会导致调用正确的 getter 方法。 唯一的区别是(理论上)性能。

在实践中,现代 HotSpot 优化器可以(在运行时)确定方法实际上是最终方法,并优化硬件调用序列以消除通过虚拟方法表进行的任何不必要的调度。 因此,无论发出 INVOKEVIRTUAL 还是 INVOKESPECIAL

1
 都没有任何区别。

1 - 假设包含调用的代码运行频率足以触发优化。

© www.soinside.com 2019 - 2024. All rights reserved.