【Kotlin】Kotlin與Java反射實踐
Google發話Kotlin成為Android開發的一級語言,然後Kotlin就瞬間火了起來,各種教程什麼的也席捲而來,不過大部分都差不多,語法、用法、規範,或是官方文件、或是中文翻譯,無論看哪個都一樣。
本篇主要是在學習中的對Kotlin反射的一點記錄,在開發Android過程中難免會用到反射來呼叫類的private方法或獲取private屬性等,Kotlin的教程上只是大致描述了一下,看了還是有點懵。
實踐
實踐是檢驗整理的唯一標準。
首先準備一個User類,當然是Kotlin實現的啦,username、nickname(私有)、age三個屬性,isChild(私有),toString方法(用java反射的時候屬性的get、set方法會自己生成)
class User constructor() { var username: String? = null private var nickname: String? = null var age: Int? = null constructor(username: String, nickname: String, age: Int?) : this() { this.username = username this.nickname = nickname this.age = age } private fun isChild(): Boolean { return age!! <= 8 } override fun toString(): String { return "User{" + "username='" + username + '\'' + ", nickname='" + nickname + '\'' + ", age=" + age + '}' } }
屬性反射
1、先建立User物件設定username和age,
2、通過反射獲取所有屬性
3、對私有屬性nickname設定值為Jack
4、列印User物件
Java實現
日誌列印public static void reflectField() { User user = new User(); user.setUsername("123456"); user.setAge(10); Field[] fields = User.class.getDeclaredFields(); for (Field field : fields) { Log.i(TAG, "fieldName = " + field.getName()); try { if("nickname".equals(field.getName())){ field.setAccessible(true); field.set(user, "Jack"); } } catch (IllegalAccessException e) { e.printStackTrace(); } } Log.i(TAG, user.toString()); }
通過外掛轉換的Kotlin實現
可以看到通過外掛轉換的Kotlin就只是用Kotlin使用Java方法而已
fun reflectField() {
val user = User()
user.username = "123456"
user.age = 10
val fields = User::class.java.declaredFields
for (field in fields) {
Log.i(TAG, "fieldName = " + field.name)
try {
if ("nickname" == field.name) {
field.isAccessible = true
field.set(user, "Jack")
}
} catch (e: IllegalAccessException) {
e.printStackTrace()
}
}
Log.i(TAG, user.toString())
}
Kotlin實現
這裡使用了Kotlin中KClass裡的declaredMemberProperties方法來獲取類內部所有屬性,它還有declaredMemberExtensionProperties方法是用於獲取類的擴充套件屬性的,還有其他一些經過過濾的屬性。最後的設定還是呼叫了Java的Field,set和get的使用都很簡單
fun reflectField() {
var user = User()
user.username = "123456"
user.age = 10
user::class.declaredMemberProperties.forEach {
Log.i(TAG, "fieldName = ${it.name}")
if ("nickname".equals(it.name)) {
it.isAccessible = true
it.javaField?.set(user,"jack")
}
}
Log.i(TAG,user.toString())
}
日誌列印
一模一樣的日誌資訊,通過Kotlin原生方法也設定了私有屬性的值
方法反射
1、先建立User物件設定username和age,
2、通過反射獲取所有方法
3、呼叫私有方法isChild
Java實現
public static void reflectMethod() {
User user = new User();
user.setUsername("123456");
user.setAge(10);
Method[] methods = User.class.getDeclaredMethods();
for (Method method : methods) {
Log.i(TAG, "methodName = " + method.getName());
if (method.getName().contains("isChild")) {
method.setAccessible(true);
try {
Log.i(TAG, "isChild = " + method.invoke(user));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
日誌列印
Kotlin實現
使用Kotlin的KClass類中declaredFunctions獲取類內所有方法,KClass類中還提供了好多經過過濾的方法,staticFunctions(靜態方法,包括父類),memberFunctions(非擴充套件非靜態方法,包括父類),memberExtensionFunctions(擴充套件方法,包括父類),declaredFunctions(非靜態方法),declaredMemberFunctions(非擴充套件非靜態方法),declaredMemberExtensionFunctions(擴充套件方法),對以上只能說非常全面。。。
fun reflectMethod() {
var user = User()
user.username = "123456"
user.age = 10
user::class.declaredFunctions.forEach {
Log.i(TAG, "methodName = ${it.name}")
if("isChild".equals(it.name)){
it.isAccessible = true
Log.i(TAG, "isChild = ${it.javaMethod?.invoke(user)}")
}
}
}
日誌列印
這裡可以發現Kotlin列印的方法中並沒有get和set方法
注:
最重要的一點就是Kotlin使用反射需要單獨引用
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
最簡單明瞭的Kotlin使用反射的方法