Home Hidden costs of using @JvmStatic
Post
Cancel

Hidden costs of using @JvmStatic

Underling hidden costs of using JvmStatic in kotlin.

Consider we have a class A in kotlin, and we use static factory pattern to getInstance of class A.

class A{
  companion object{
      @JvmStatic
      fun getInstance():A = A()
  }
}

Now the only reason we @JvmStatic is when we have inter-op from java, where an instance of class A is called from java. Let’s look into underlying java code thats generated when we use @JvmStatic for class A

public final class A {
   public static final A.Companion Companion = new A.Companion((DefaultConstructorMarker)null);

   @JvmStatic
   @NotNull
   public static final A getInstance() {
      return Companion.getInstance();
   }

   @Metadata(
      mv = {1, 1, 15},
      bv = {1, 0, 3},
      k = 1,
      d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0000\b\u0086\u0003\u0018\u00002\u00020\u0001B\u0007\b\u0002¢\u0006\u0002\u0010\u0002J\b\u0010\u0003\u001a\u00020\u0004H\u0007¨\u0006\u0005"},
      d2 = {"Lproblems/Arrays/A$Companion;", "", "()V", "getInstance", "Lproblems/Arrays/A;", "kotlin-exercises"}
   )
   public static final class Companion {
      @JvmStatic
      @NotNull
      public final A getInstance() {
         return new A();
      }

      private Companion() {
      }

      // $FF: synthetic method
      public Companion(DefaultConstructorMarker $constructor_marker) {
         this();
      }
   }
}

Please note there is an extra method getInstance in the outer class A.

Now when we use it without @JvmStatic following code gets generated.

public final class A {
   public static final A.Companion Companion = new A.Companion((DefaultConstructorMarker)null);

   @Metadata(
      mv = {1, 1, 15},
      bv = {1, 0, 3},
      k = 1,
      d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0000\b\u0086\u0003\u0018\u00002\u00020\u0001B\u0007\b\u0002¢\u0006\u0002\u0010\u0002J\u0006\u0010\u0003\u001a\u00020\u0004¨\u0006\u0005"},
      d2 = {"Lproblems/Arrays/A$Companion;", "", "()V", "getInstance", "Lproblems/Arrays/A;", "kotlin-exercises"}
   )
   public static final class Companion {
      @NotNull
      public final A getInstance() {
         return new A();
      }

      private Companion() {
      }

      // $FF: synthetic method
      public Companion(DefaultConstructorMarker $constructor_marker) {
         this();
      }
   }
}

Notice the absence of the getInstance in the outer class. In case we don’t use @JvmStatic from java getting instance of class A would be with one extra Companion as shown below.

 A.Companion.getInstance()

Now given the limitation of only 65,536 method counts in a single dex (for android), using @JvmStatic just to reduce Companion keyword is costly affair in Android.

More reading:

1.@JvmStatic
2.When and Why to use @JvmStatic.

This post is licensed under CC BY 4.0 by the author.