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"