Why and when to use @JvmStatic with companion objects?

前端 未结 3 1976
栀梦
栀梦 2020-12-23 09:30

I\'m trying to understand the difference between using/not using @JvmStatic, and when I should use either one.

So, with Kotlin and Java, I can do this:

3条回答
  •  情话喂你
    2020-12-23 09:49

    In Kotlin, the companion object can be us used to imitate static behaviour, calls look like static calls in Java, the “Companion“ isn’t part of if. If used in Java though, the companion object has to be named, unless @JvmStatic is applied. It’d look less idiomatic otherwise.

    TestKotlin.getSomeString() //this should be preferred whenever possible
    

    Stated in the docs:

    Companion Objects

    An object declaration inside a class can be marked with the companion keyword:

    class MyClass {
       companion object Factory {
           fun create(): MyClass = MyClass()
       }
    }
    

    Members of the companion object can be called by using simply the class name as the qualifier:

    val instance = MyClass.create()
    

    ...

    However, on the JVM you can have members of companion objects generated as real static methods and fields, if you use the @JvmStatic annotation. See the Java interoperability section for more details.

    Note that it will generate an additional method as stated here:

    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.

    Let's see an example:

    The following class

    class Outer {
        companion object {
            fun callMe() = ""
        }
    }
    

    looks like this on bytecode level, here represented as Java code:

    @Metadata(...)
    public final class Outer {
       public static final Outer.Companion Companion = new Outer.Companion((DefaultConstructorMarker)null);
    
       @Metadata(...)
       public static final class Companion {
          @NotNull
          public final String callMe() {
             return "";
          }
    
          private Companion() {
          }
    
          // $FF: synthetic method
          public Companion(DefaultConstructorMarker $constructor_marker) {
             this();
          }
       }
    }
    

    If @JvmStatic is being applied to callMe method though, the bytecode changes to the following:

    @Metadata(...)
    public final class Outer {
       public static final Outer.Companion Companion = new Outer.Companion((DefaultConstructorMarker)null);
    
       @JvmStatic
       @NotNull
       public static final String callMe() {
          return Companion.callMe();
       }
    
       @Metadata(...)
       public static final class Companion {
          @JvmStatic
          @NotNull
          public final String callMe() {
             return "";
          }
    
          private Companion() {
          }
    
          // $FF: synthetic method
          public Companion(DefaultConstructorMarker $constructor_marker) {
             this();
          }
       }
    }
    

    You can see, correctly documented, the static callMe function, as part of Outer is generated:

    @JvmStatic
    @NotNull
    public static final String callMe() {        
        return Companion.callMe();
    }
    

提交回复
热议问题