After Kotlin was adopted as the official Android development language, more and more Android developers flocked to Kotlin. While Kotlin is compatible with Java, there are many differences in the use of the static keyword, such as the companion Object, which is used instead of static. When called with reflection, it is not as straightforward as static. Static methods that you want to call with reflection cannot be called, so you can see it through the bytecode implementation, by the way (●>∀<●).

How to view kotlin bytecode

Kotlin->Show Kotlin bytecode open the Kotlin bytecode interface to view the Kotlin file in bytecode form. The interface is as follows:

Static (Object) static

In Kotlin, we can implement a singleton directly with Object, by calling methods in the Object singleton similar to Java static methods.

object MyObject {
    val x = "x"

    public fun foo(): String {
        return x
    }
}
Copy the code

For this simple Object singleton, the bytecode we see looks like this (omitting part of the bytecode) :

  private final static Ljava/lang/String; x = "x"public final getX()Ljava/lang/String; . public finalsetX(Ljava/lang/String;) V .. public final foo()Ljava/lang/String; . public final static Lcom/tanzhouedu/testapplication/MyObject; INSTANCECopy the code

As you can see, Kotlin declared an INSTANCE static variable in the class to implement the singleton effect.

So when we call foo() in the Java language, we take the INSTANCE static variable and continue.

My Companion Object is static

This time, we implement static variable and method calls with Companion objects as follows:

class MyClass {

    companion object {
        val x = "x"

        fun foo(): String {
            return x
        }
    }
}
Copy the code

The bytecode we see looks like this (part of the bytecode is omitted) :


// access flags 0x1A
private final static Ljava/lang/String; x = "x"

// access flags 0x19
public final static Lcom/windinwork/myapplication/bytecode/MyClass$Companion; Companion
  
// access flags 0x31
public final class com/windinwork/myapplication/bytecode/MyClass$Companion{ // access flags 0x11 public final getX()Ljava/lang/String; @Lorg/jetbrains/annotations/NotNull; () // invisible L0 LINENUMBER 6 L0 INVOKESTATIC com/windinwork/myapplication/bytecode/MyClass.access$getX$cp()Ljava/lang/String; ARETURN ... // access flags 0x11 public final foo()Ljava/lang/String; .Copy the code

The variable x declared in the Companion Object is compiled as a static variable of MyClass, while the methods getX() and foo() are member methods of MyClass$Companion. As you can see, MyClass holds a reference to MyClass$Companion via a static variable, so when we call foo() and call x, we essentially call the static variable Companion. Thus our call to the Companion Object singleton in Java looks like this

Implement static methods in Java through @jVMStatic

From the above two examples, we can see that the variables in our declared singleton are static and can be retrieved directly by reflection. None of the methods use the static modifier. If left unhandled, we cannot make direct reflection calls to foo() methods like Java static methods when making reflection calls in Java, but instead use the Companion static variable in Object singletons or when using Companion Object singletons. Make reflection calls indirectly.

So, can we make reflection calls to Java static methods like these singleton methods? This is where we use the @jVMStatic annotation.

At this point we can see that foo() is also static, so that we call foo() the same way we call it in Java.

Five, the conclusion

As you can see from the above, kotlin does not generate static methods in bytecode without the @jVMstatic annotation. Of course, we can call static methods in Kotlin, such as myClass.foo (), but it behaves differently in Java. Static variable and method implementation in Kotlin