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());
    }

日志打印

java和kotlin哪个好找工作_反射



通过插件转换的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())
    }

日志打印

java和kotlin哪个好找工作_User_02


一模一样的日志信息,通过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();
                }
            }
        }
    }

日志打印

java和kotlin哪个好找工作_静态方法_03

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方法

java和kotlin哪个好找工作_反射_04


注:

最重要的一点就是Kotlin使用反射需要单独引用

compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"