Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is it possible for a JvmStatic method to access and modify state?

I would've assumed that a method annotated with @JvmStatic would be unable to access, let alone modify, a class property.

Based on the following this is not the case. This code clearly updates state, printing 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}")
}
like image 601
iluvfugu Avatar asked Oct 27 '25 14:10

iluvfugu


2 Answers

I was also surprised by this. In fact, because Foo is an object, the field bar is actually a static field on the JVM. That's why it's not a problem to access it from a static method.

The decompiled Java code of your class is the following:

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

However, I would avoid doing this. It's unexpected and doesn't really convey the intent.

like image 199
Joffrey Avatar answered Oct 30 '25 14:10

Joffrey


I assume you wouldn't be surprised without the @JvmStatic annotation; objects are allowed to have mutable state just as classes are.

But @JvmStatic/@JvmField/@JvmOverloads are all designed not to change any behavior from Kotlin's point of view, only the way it's exposed to Java. There is still a this inside the method (referring to the object Foo) just like there would be without the annotation. From the documentation:

If you use this annotation, the compiler will generate both a static method in the enclosing class of the object and an instance method in the object itself...

Same for named objects:

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

In Java:

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

The instance method obviously can manipulate the instance state; while the static method can simply call the instance one and be defined as

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

(even if according to @Joffrey's answer this isn't the way the current implementation works).

like image 34
Alexey Romanov Avatar answered Oct 30 '25 14:10

Alexey Romanov



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!