kotlin
在被欽定爲Android
的官方開發語言後,愈來愈多的Android
開發者投向kotlin
的懷抱。儘管kotlin
兼容Java
,但在使用上仍是有很大不一樣的,就像static
關鍵字,咱們能夠用companion object
來替代static
,當咱們用反射去調用時,會發現調用時並不像static
那樣直接,筆者在平常使用中就遇到這樣的問題,想拿反射去調用靜態方法時沒法調用,因此便經過字節碼的實現來一窺究竟,順便水一篇文章(●>∀<●)。java
咱們經過Tools->Kotlin->Show Kotlin bytecode
打開Kotlin
字節碼界面,查看Kotlin
文件的字節碼形式。界面以下:bash
在Kotlin
中,咱們能夠經過Object
來直接實現一個單例,經過對Object
單例中方法的調用來實現相似於Java
中static
方法的調用。app
object MyObject {
val x = "x"
public fun foo(): String {
return x
}
}
複製代碼
對於這個簡單的Object
單例,咱們看到的字節碼是這樣的(省略部分字節碼):ui
private final static Ljava/lang/String; x = "x"
public final getX()Ljava/lang/String;
...
public final setX(Ljava/lang/String;)V
..
public final foo()Ljava/lang/String;
...
public final static Lcom/tanzhouedu/testapplication/MyObject; INSTANCE
複製代碼
能夠看到,Kotlin
在該類中聲明瞭一個INSTANCE
的static
變量來實現單例效果。spa
因此咱們在Java
語言中調用foo()
方法是這樣的,即拿到INSTANCE
靜態變量再繼續調用。code
這一次,咱們經過Companion Object
伴生對象來實現靜態的變量和方法調用,代碼以下:cdn
class MyClass {
companion object {
val x = "x"
fun foo(): String {
return x
}
}
}
複製代碼
咱們看到的字節碼是這樣的(省略部分字節碼):對象
// 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;
...
複製代碼
咱們來分析一下這段字節碼,能夠看到,咱們在Companion Object
中聲明的變量x
,編譯以後是做爲MyClass
的靜態變量存在,而方法getX()和foo()是做爲MyClass$Companion
的成員方法存在。咱們能夠看到,MyClass
經過一個靜態變量Companion
持有MyClass$Companion
的引用,因此咱們在訪問x變量和調用foo()
方法時,實質上是經過對Companion
這一靜態變量進行方法調用,因而咱們在Java中對Companion Object
單例的調用是這樣的blog
經過以上兩個例子,咱們發現,在咱們聲明的單例中,變量是採用了static
修飾的,咱們經過反射能夠直接拿到變量。而方法都沒有使用static
修飾。若是不加處理,在咱們用Java
進行反射調用時,咱們沒法對foo()方法像Java
的static
方法進行直接的反射調用,而要經過Object
單例中的INSTANCE
或者使用Companion Object
單例時的Companion
靜態變量,間接地進行反射調用。開發
那麼,咱們可不能夠像對這些單例的方法,進行Java
的static
方法的反射調用呢?這時候咱們就要使用@JvmStatic
註解。
這時候咱們就能夠看到foo()
方法也被static
修飾了,這樣咱們在調用foo()
方法的方式和在Java
調用時的是一致的了。
從上面咱們能夠看到,若是不經過@JvmStatic
註解,kotlin在字節碼中是不產生static
方法的,固然咱們在kotlin
使用中是能夠直接調用,如MyClass.foo()
的,而放到Java
上表現就明顯不一樣了。這篇文章主要是寫給Java
轉向kotlin
時對kotlin
中static
變量和方法實現有疑問的同窗,但願能有所幫助。