關於在Kolint中儲存常量,這篇短文講述了一些可供選擇的方案,再者,提出了一些可能會吸引人去踏入的陷阱。但在此以前,讓咱們先聊一聊被編譯成Java後的Kotlinbash
Kotlin的魅力之一就是你能很容易地將一些複雜的代碼簡單化,讓編譯器去代替你作繁雜的工做。
data class
就是一個很好的例子,短短一行代Kotlin碼替代了數十行Java代碼。ide
可是能力越大,責任越大。咱們很容易就會讓Kotlin編譯器產生一些原本就能夠被簡化(suboptimal)的字節碼(bytecode),尤爲是作安卓開發的。面對衆多的類、方法和對象分配,須要意識到會不會出現上述狀況。同時JetBrains也提供給了開發者一些集成到了AndroidStudio(固然還有IntelliJ IDEA)反編譯工具(Kotlin編譯成Java),幫助咱們瞭解和優化代碼自己函數
關於decompile的連接在文末,不過多贅述工具
接下來說到優化
關於頂層常量,固然變量和方法均可以定義在頂層ui
Kotlin中沒有static關鍵字,若是你想在類中聲明靜態方法或屬性,就要把他們放在companion object(伴生對象)中this
class Constants {
companion object {
val FOO = "foo"
}
}
複製代碼
當要在其它地方用到的時候,能夠像在Java那樣Constants.FOO
idea
如今看一看反編譯工具生成對應的Java代碼(有簡化)spa
public final class Constants {
@NotNull
private static final String FOO = "foo";
public static final Constants.Companion Companion = new Constants.Companion((DefaultConstructorMarker)null);
public static final class Companion {
@NotNull
public final String getFOO() {
return Constants.FOO;
}
private Companion() {
}
// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
}
複製代碼
注意到很重要的一點:Constants.FOO
被編譯成Java的Constants.Companion.getFOO()
,看起來很不優雅,接下來的方法能夠避免這個狀況code
使用條件
companion object
屬性,或object
屬性把上面的Kotlin代碼改一改,變成
class Constants {
companion object {
const val FOO = "foo"
}
}
複製代碼
生成對應的Java代碼
public final class Constants {
@NotNull
public static final String FOO = "foo";
public static final Constants.Companion Companion = new Constants.Companion((DefaultConstructorMarker)null);
public static final class Companion {
private Companion() {
}
// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
}
複製代碼
常量FOO原來對應的getter
不見了,FOO的訪問權限從private
變成了public
,因而在Java中能夠直接Constants.FOO
。可是,Companion
這個沒用的類依然存在。接下來是另外一個變通方法
const val
的本質能夠類比C語言的#define
定義常量
把上面const去掉,給FOO加上JvmField註解 生成的Java代碼原文沒給
class Constants {
companion object {
@JvmField val FOO = Foo() //Foo()是爲了說明不限定於原始類型
}
}
複製代碼
生成的Java代碼基本和const val的沒區別,有一個重要區別就是,訪問const val
的常量時,會變成內聯常量,@JvmField
註解的常量則不會,看下面代碼
fun main(args: Array<String>) {
println(Constants.FOO)
}
複製代碼
編譯成Java後 @JvmField
註解版本
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
Foo var1 = Constants.FOO; //直接訪問
System.out.println(var1);
}
複製代碼
const val
修飾版本
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
String var1 = "foo"; //內聯
System.out.println(var1);
}
複製代碼
若是一個類只是用來裝載常量,那咱們能夠放心大膽地「丟棄這個類和companion object」,使用Kotlin的文件級屬性(頂層屬性) 直接在kt文件中
const val FOO = "foo"
/* 能夠在此聲明頂層函數,在此不作討論 */
/* 其它類(也能夠不聲明,專門用這個文件存放常量) */
複製代碼
生成對應的Java代碼(或許就是你在使用Java時會寫上的代碼)
public final class ConstantsKt {
@NotNull
public static final String FOO = "foo";
}
複製代碼
在Kotlin裏,你能夠不帶類名地使用這些頂層屬性,好比println(FOO)
,在Java中使用這些值的時候,你須要ConstantsKt .FOO
。下面的註解能夠去掉Kt後綴
@file:JvmName("Constants")
複製代碼
使用註解後生成的Java代碼
public final class Constants {
@NotNull
public static final String FOO = "foo";
}
複製代碼
即便Kotlin中沒有static
關鍵字,咱們也能夠很容易定義全局使用的常量,但同時也很容易使編譯器產生沒必要要的字節碼。在decompiler的幫助下,咱們能更好地理解和使用Kotlin