为什么JvmStatic方法可以访问和修改状态?

问题描述 投票:3回答:2

我以为带有@JvmStatic注释的方法将无法访问,更不用说修改类属性了。

基于以下情况,并非如此。此代码清楚地更新状态,打印From main - 11

object Foo {
    var bar = 5

    @JvmStatic
    fun updateBar(updateVal : Int) {
        println("bar = $bar")
        bar += updateVal
        println("bar = $bar")
    }
}

fun main() {
    Foo.updateBar(6)
    println("From main - ${Foo.bar}")
}
kotlin static-methods
2个回答
4
投票

我也为此感到惊讶。实际上,因为Fooobject,所以字段bar实际上是JVM上的静态字段。这就是为什么从静态方法访问它不是问题。

您的类的反编译Java代码如下:

public final class Foo {
   private static int bar;
   public static final Foo INSTANCE;

   public final int getBar() {
      return bar;
   }

   public final void setBar(int var1) {
      bar = var1;
   }

   @JvmStatic
   public static final void updateBar(int updateVal) {
      String var1 = "bar = " + bar;
      boolean var2 = false;
      System.out.println(var1);
      bar += updateVal;
      var1 = "bar = " + bar;
      var2 = false;
      System.out.println(var1);
   }

   private Foo() {
   }

   static {
      Foo var0 = new Foo();
      INSTANCE = var0;
      bar = 5;
   }
}

但是,我会避免这样做。这是意外的,并没有真正传达出意图。


2
投票

我想如果没有@JvmStatic注释,您不会感到惊讶;对象与类一样具有可变的状态。

但是@JvmStatic /@JvmField/ @JvmOverloads都被设计为从Kotlin的角度来看,不改变任何行为,仅是将其公开给Java的方式。就像没有注释一样,方法内部仍然有一个this(指的是object Foo)。从the documentation

如果使用此批注,则编译器将在对象的封闭类中生成静态方法,并在对象本身中生成实例方法...

与命名对象相同:

object Obj {
    @JvmStatic fun callStatic() {}
    fun callNonStatic() {}
}

在Java中:

Obj.callStatic(); // works fine
Obj.callNonStatic(); // error
Obj.INSTANCE.callNonStatic(); // works, a call through the singleton instance
Obj.INSTANCE.callStatic(); // works too

实例方法显然可以操纵实例状态;而静态方法可以简单地将实例调用为一个,并定义为

public static final void updateBar(int updateVal) {
    Foo.INSTANCE.updateBar(updateVal);
}

(即使根据@Joffrey的回答,这也不是当前实现的工作方式。

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