Acompanion object
是一个实数class
被调用的实例Companion
。因此,当您从 Java 调用 Kotlin 代码时,Companion
首先会在后台实例化该类的一个对象。为了理解这一点,让我们考虑一个简单的例子。
幕后无@JvmStatic
科特林代码
class Plant {
companion object {
fun waterAll() { }
}
}
反编译的Java代码
public final class Plant {
public static final Plant.Companion Companion = new Plant.Companion();
public static final class Companion {
public final void waterAll() { }
private Companion() { }
}
}
正如您在上面简化的反编译 Java 代码中看到的那样,Companion
生成了一个名为的类来表示companion object
. 该类拥有该类Plant
的单例实例。该实例也被命名为. 这就是您需要使用 Java调用函数/属性的原因:new Plant.Companion()
Plant.Companion
Companion
companion object
Plant.Companion
Plant.Companion.waterAll();
在幕后与@JvmStatic
科特林代码
class Plant {
companion object {
@JvmStatic
fun waterAll() { }
}
}
反编译的Java代码
public final class Plant {
public static final Plant.Companion Companion = new Plant.Companion();
@JvmStatic
public static final void waterAll() { Companion.waterAll();}
public static final class Companion {
@JvmStatic
public final void waterAll() { }
private Companion() { }
}
}
在 Kotlin中注解 a 的函数时companion object
,除了非静态函数之外,还会生成@JvmStatic
一个纯static
函数。因此,现在您可以不使用Java 更惯用的名称来调用该函数:waterAll()
waterAll()
Companion
Plant.waterAll();
辛格尔顿
在这两种情况下都会生成单例模式。如您所见,在这两种情况下,Companion
实例都持有单例对象new Plant.Companion()
,并且构造函数是private
为了防止多个实例。
Javastatic
关键字不会创建单例。companion object
只有在 Kotlin 中创建一个然后从 Java 中使用它时,您才会获得单例功能。要从 Java 中获取单例,您需要编写单例模式,其代码类似于上面显示的反编译 Java 代码。
表现
在内存分配方面没有性能增益或损失。原因是,正如您在上面的代码中看到的,static
生成的额外函数将其工作委托给非静态函数Companion.waterAll()
。这意味着,无论有没有Companion
,都需要创建实例。@JvmStatic
@JvmStatic
除了生成的额外方法之外,这两种设置的行为都是相同的。在 Android 中,如果您担心方法计数,您可能需要注意这一点,因为会为每个带注释的函数创建一个额外的副本。
何时使用@JvmStatic
当您知道您的 Kotlin 代码不会在 Java 中使用时,您不必担心添加@JvmStatic
注解。这使您的代码更干净。但是,如果您的 Kotlin 代码是从 Java 调用的,则添加注释是有意义的。这将防止您的 Java 代码在任何地方都被该名称污染Companion
。
它不像任何一方的附加关键字。如果你@JvmStatic
在一个地方添加,你可以防止Companion
在数千个地方写额外的单词,无论你在哪里调用这个函数。这对库创建者特别有用,如果他们添加@JvmStatic
到他们的 Kotlin 库中,该库的用户将不必Companion
在他们的 Java 代码中使用这个词。
而已!希望这有助于更清晰地了解@JvmStatic
.