由于 Kotlin 不允许您像 Java 中的 static
成员那样直接在 class
中声明常量,因此我们有几种方法可以在 Kotlin 中实现.我的问题是,每个选项的性能成本是多少,哪个更便宜?我不想知道哪个更具可读性或被认为是最佳实践,我只想从性能的角度来看。
选项 1:使用伴随对象
所以代码看起来像这样:
class Thing {
companion object {
const val TAG = "Thing"
}
...
}
在 Java 中是这样的:
public final class Thing {
public static final String TAG = "Thing";
public static final Thing.Companion Companion = new Thing.Companion((DefaultConstructorMarker)null);
public static final class Companion {
private Companion() {
}
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
...
}
它创建了这个内部类 Companion
并实例化了它。这有多贵?
选项2:将其声明为顶级变量
所以这样:
const val TAG = "Thing"
class Thing {
...
}
变成这样:
public final class ThingKt {
public static final String TAG = "Thing";
}
public final class Thing { ... }
它创建了一个带有static
成员的新类。这与使用对象来存储它有何不同?
选项 3:使用外部对象
像这样:
object ThingConstants {
const val TAG = "Thing"
}
class Thing { ... }
在 Java 中是这样的:
public final class ThingConstants {
public static final String TAG = "Thing";
public static final ThingConstants INSTANCE;
... // Private constructor
}
public final class Thing { ... }
与声明为顶级非常相似,除了创建的类有一个在私有(private)构造函数中初始化的 INSTANCE
字段。与使用顶级变量相比,这有多昂贵?
选项 4:删除 const 修饰符
所以你只需使用旧的val
:
class Thing {
val TAG = "Thing"
...
}
这对我来说是个谜。它不会创建任何额外的类,但也不会获得 const
修饰符的好处。这意味着该类的每个实例都将拥有自己的 TAG
实例,并为其生成 getter 和 setter,对吧?但我也是read JVM 将其优化为常量。所以这个选项比我最初想象的要多。
最佳答案
选项 1-3 在性能方面是相同的,因为它们都是 const
,所以它们在编译时使用的任何地方都是内联的。
选项 4 不会为类的每个实例创建 String 的重复实例。相反,该类的每个实例都将有一个指向同一个共享实例的成员字段。就性能而言,从技术上讲,每次检索时都必须调用 getter 方法,但我希望现代 VM 能够在运行时优化该开销。
选项 1-3 确实会创建额外的 Java 类定义,因此它们的前期内存开销要多一些。但是,如果您在这些对象或顶级文件中已经有其他成员,那么无论如何您已经拥有了这些类。选项 4 在类中有一个额外的字段,因此如果类的实例很多,它可能会更重。
关于java - 在 Kotlin 中声明常量的所有方式之间的性能差异是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70526750/