object class 中的 static 方法

事情是从一个 Unit Test开始的。

我写了一个 object 的类,里边有简单的几个方法,然后开始用 Mocito 写一个 Unit Test 进行测试,方便起见,我抽象一下如下:

object A {
    fun hello(): String {
        println("Hello")
        return "hello"
    }

    fun world(): String {
        println("World!")
        return "World"
    }
}
复制代码

最终发现问题其实是在于 object 类并不是静态类,object 中定义的方法也并不是 static 的方法,这个可以通过编译后的 class file 看出来:

// access flags 0x2
  private <init>()V
   L0
    LINENUMBER 14 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
    RETURN
   L1
    LOCALVARIABLE this LA; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x19
  public final static LA; INSTANCE
  @Lorg/jetbrains/annotations/NotNull;() // invisible
复制代码

object 本身就是一个构造函数为 private 的普通类,同时提供了一个 public 的 INSTANCE,就是通常我们说的单例对象。

上面的发现可能是大多数人比较清楚的 kotlin 的一个特点,因为我们偶尔也会在 java 中调 A,就是通过 A.INSTANCE.xxx

但我忽略的是 A 中的方法其实也并不是 static 的,而是普通的 final 方法:

// access flags 0x11
  public final hello()Ljava/lang/String;
  @Lorg/jetbrains/annotations/NotNull;() // invisible
   L0
    LINENUMBER 16 L0
    LDC "Hello"
    ASTORE 1
   L1
复制代码

因此无法直接使用 mockStatic 来对 hello() 进行mock,因为它本质上并不是 static 的。

想要解决这个问题也比较简单,为 hello() 添加 @JvmStatic 即可,可以看到加上这个注解之后,byecode 相对应增加了一个 static :

// access flags 0x19
  public final static hello()Ljava/lang/String;
  @Lkotlin/jvm/JvmStatic;()
  @Lorg/jetbrains/annotations/NotNull;() // invisible
   L0
    LINENUMBER 20 L0
    LDC "Hello"
    ASTORE 0
   L1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
复制代码

这种情况下再使用 mockito 的 mockStatic 就没有问题了。

但是到这里我又有一个问题了,为什么 kotlin 的 object class 不默认将方法作为 static 的呢?并且 kotlin 中也没有 static 的关键字,这种语言设计的原因又是什么呢?

个人认为是由于 kotlin 设计之初的一个原则就是:一切皆是对象。在 Java 中 static 的变量与 object 有很大的区别,这意味着你没有办法去基于此实现接口,或者是将 static 的变量作为参数传给函数。

猜你喜欢

转载自juejin.im/post/7074474944880443423