Почему метод JvmStati c может получать доступ и изменять состояние? - PullRequest
3 голосов
/ 09 мая 2020

Я бы предположил, что метод, помеченный @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}")
}

Ответы [ 2 ]

4 голосов
/ 09 мая 2020

Меня это тоже удивило. Фактически, поскольку Foo является object, поле bar фактически является полем c на JVM. Вот почему получить к нему доступ из метода stati c не проблема.

Декомпилированный 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 голосов
/ 10 мая 2020

Полагаю, вы не удивитесь без аннотации @JvmStatic; объекты могут иметь изменяемое состояние, как и классы.

Но @JvmStatic / @JvmField / @JvmOverloads все разработаны так, чтобы не изменять никакого поведения с точки зрения Kotlin , только так выставлено на Java. Внутри метода все еще есть this (относящийся к object Foo), как и без аннотации. Из документации :

Если вы используете эту аннотацию, компилятор сгенерирует как метод stati c во включающем классе объекта, так и метод экземпляра в объекте сам ...

То же самое для именованных объектов:

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

Очевидно, что метод экземпляра может управлять состоянием экземпляра ; в то время как метод stati c может просто вызвать экземпляр один и быть определен как

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

(даже если в соответствии с ответом @Joffrey это не так, как работает текущая реализация).

...