Kotlin使用Java反射Api操作KClass時遇到的變量作用域問題記錄

Kotlin本身帶的反射Api依據官方文檔來看貌似是殘缺的,想實現完整的反射支持只能調用Java的反射Api,類似下面這樣:

val test = Test::class.java

這樣就可以通過test對象調用Java的反射Api了,這樣在操作Java Class的時候是沒問題的,但是操作Kotlin的KClass就會出現變量作用域的問題……

問題的根源在於Kotlin代碼在翻譯成Java代碼後無論你先前聲明的成員變量的作用域是公有還是私有,都會被翻譯成私有,並輔以一堆Get、Set方法用來操作該變量。這似乎是挺符合Java世界的標準的,在Kotlin下訪問一個變量會自動調用其Get、Set方法。但在反射的這個應用場景下就會出問題。看一下下面這個語句:

test.getFields().forEach {
    println(it.name)
}

上面這段代碼會輸出什麼?

什麼也沒有……

包括你使用test.getField("testVar")時也會給你拋出一個找不到成員變量的異常。這就是問題表現。你不再能像之前習慣的那樣直接操作字段了……

這個問題除了老老實實調用對應的Get、Set方法操作外還可以通過將成員變量聲明為JvmField的形式防止其被翻譯成私有:

class Test {
    @JvmField
    val testVar: String? = null 
}

不過我更建議還是老老實實麻煩一點調用Get、Set方法操作……因為直接操作變量的話將來一旦類的內部對變量的讀寫進行了一些預處理操作,直接通過訪問變量字段的方式操作變量就無法觸發這些操作,代碼維護起來會很麻煩。