Kotlin(十)之反射

反射

  1. Kotlin的类引用使用KClass表示,java的类引用对象是Class对象.

  2. 依赖反射包

    compile 'org.jetbrains.kotlin:kotlin-reflect:1.3.31'
    
  3. 反射API层次结构

    Kotlin反射类图

获取类信息

  1. 准备数据

    import kotlin.reflect.full.*
    
    annotation class Monitor
    annotation class City(val name: String = "Beijing")
    
    @Monitor
    @City
    class Person(age: Int) {
        var name: String = "jannal"
    
        private constructor() : this(30)
    
        constructor(name: String) : this(15) {
            println("一个参数的构造函数${name}")
        }
    
        fun info() {
            println("无参数的info")
        }
    
        fun info(name: String) {
            println("有name参数的info,name:${name}")
        }
        //嵌套类
        class inner
    }
    
    fun Person.run() {
        println("扩展方法run")
    }
    
    
  2. 获取类相关信息

    fun main() {
        val personKClass = Person::class
        val constructors = personKClass.constructors
        println("Person的全部构造器:")
        /**
         * fun <init>(): cn.jannal.reflection.Person
         * fun <init>(kotlin.String): cn.jannal.reflection.Person
         * fun <init>(kotlin.Int): cn.jannal.reflection.Person
         */
        constructors.forEach { println(it) }
    
        //fun <init>(kotlin.Int): cn.jannal.reflection.Person
        println("Person的主构造器:${personKClass.primaryConstructor}")
    
        println("Person全部方法:")
        val functions = personKClass.functions
        /**
         * fun cn.jannal.reflection.Person.info(): kotlin.Unit
         * fun cn.jannal.reflection.Person.info(kotlin.String): kotlin.Unit
         * fun cn.jannal.reflection.Person.equals(kotlin.Any?): kotlin.Boolean
         * fun cn.jannal.reflection.Person.hashCode(): kotlin.Int
         * fun cn.jannal.reflection.Person.toString(): kotlin.String
         * */
        functions.forEach { println(it) }
    
        println("Person声明的所有方法(不包括继承的方法):")
        /**
         * fun cn.jannal.reflection.Person.info(): kotlin.Unit
         * fun cn.jannal.reflection.Person.info(kotlin.String): kotlin.Unit
         */
        personKClass.declaredFunctions.forEach { println(it) }
    
        println("Person声明的所有成员方法(不包括继承的方法):")
        /**
         * fun cn.jannal.reflection.Person.info(): kotlin.Unit
         * fun cn.jannal.reflection.Person.info(kotlin.String): kotlin.Unit
         */
        personKClass.declaredMemberFunctions.forEach { println(it) }
    
        println("Person声明的所有属性(不包括继承的属性):")
        //var cn.jannal.reflection.Person.name: kotlin.String
        personKClass.declaredMemberProperties.forEach { println(it) }
    
        println("Person的全部注解:")
        /**
         * @cn.jannal.reflection.Monitor()
         * @cn.jannal.reflection.City(name=Beijing)
         */
        personKClass.annotations.forEach { println(it) }
    
    
        println("Person的嵌套类:")
        //class cn.jannal.reflection.Person$inner
        personKClass.nestedClasses.forEach { println(it) }
    }
    

函数引用

  1. Kotlin允许通过::ClassName来引用改类的主构造器

    class Foo(var name: String = "jannal")
    
    //test要求传入一个(String) -> Foo类型的参数
    fun test(foo: (String) -> Foo) {
        val x: Foo = foo("jannal2")
        println(x.name)
    }
    
    fun main() {
        test(::Foo)
    }
    
  2. 如果要获取Kotlin构造器引用对应的java构造器对象,可以通过调用KFunction的扩展属性javaConstructor

    ::Foo.javaConstructor
    ::Foo.javaClass
    ::Foo.javaMethod
    
  3. 函数引用,::MethodName可以获取特定函数的引用。如果有多个重载函数,kotlin可通过上下文推断,如果无法推断就会报错,此时需要手动指定

    fun isSmall(i: Int) = i < 5
    fun isSmall(s: String) = s.length < 5
    
    fun main() {
        //系统可推断出来是isSmall(i: Int)
        val list = listOf(10, 20, 30, 100, -1, -20)
        list.filter(::isSmall).forEach { println(it) }
        //系统可推断出来是 isSmall(s: String)
        val list2 = listOf("10111", "2011", "30")
        list2.filter(::isSmall).forEach { println(it) }
    
        //系统无法推断,需要手动指定
        //val f =::isSmall
        val f: (String) -> Boolean = ::isSmall
        println(f)
    }
    
    
  4. 如果需要引用类的成员方法或者扩展方法,需要进行限定

    String::toCharArray
    引用类型不是()->CharArray 而是String.()->CharArray
    
  5. 函数组合

    fun abs(d: Double): Double = if (d < 0) -d else d
    fun sqrt(d: Double): Double = Math.sqrt(d)
    
    fun composition(fun1: (Double) -> Double, fun2: (Double) -> Double): (Double) -> Double {
        return { x -> fun2(fun1(x)) }
    }
    
    fun main() {
        println(abs(-3.2))
        val f = composition(::abs, ::sqrt)
        println(f(-2.0))
    }
    

创建对象

  1. 准备数据

    class Student(var name: String) {
        var age: Int = 10
    
        constructor() : this("jannal") {
            this.age = 20
        }
    
        constructor(name: String, age: Int) : this() {
            this.age = age
            this.name = name
        }
    }
    
  2. 创建对象

    fun main() {
        val studentKClass = Student::class
        val createInstance = studentKClass.createInstance();
        //name:jannal,age:20
        println("name:${createInstance.name},age:${createInstance.age}")
    
        //获取所有构造器
        studentKClass.constructors.forEach {
            if (it.parameters.size == 2) {
                val instance = it.call("jannal1", 50)
                //name:jannal1,age:50
                println("name:${instance.name},age:${instance.age}")
    
            }
        }
    }
    

调用方法

  1. 准备数据

    class Car {
        fun run() {
            println("run...")
        }
    
        fun printPrice(price: Double) {
            println("printPrice:${price}")
        }
    }
    
  2. 调用方法使用call函数

    fun main() {
        val carKClass = Car::class
        val createInstance = carKClass.createInstance()
    
        val declaredFunctions = carKClass.declaredFunctions
        declaredFunctions.forEach {
    
            when (it.parameters.size) {
                // 函数具有三个参数,对应两个参数,因为还有一个this
                1 -> {
                    it.call(createInstance)
                }
                // 函数具有2个参数,对应1个参数,因为还有一个this
                2 -> {
                    it.call(createInstance, 13.00)
                }
            }
        }
    }
    

访问属性

  1. 设置或者访问属性

    class User {
        var name: String = "username"
        val age: Int = 16
    }
    
    fun main() {
        val userKClass = User::class
        val user = userKClass.createInstance()
        //获取声明的属性
        userKClass.declaredMemberProperties.forEach {
            when (it.name) {
                "name" -> {
                    //获取KProperty对象之后,通过get获取属性值
                    //如果要设置值通过KMutableProperty对象
                    val mp = it as KMutableProperty1<User, Any>
                    mp.set(user, "jannal")
                    //jannal
                    println(it.get(user))
                }
                "age" ->{
                    //只读属性只能通过get
                    println(it.get(user))
                }
            }
        }
    }
    
  2. kotlin也提供了::PropertyName来获取属性引用

     val kProperty1: KProperty1<User, Int> = User::age
    
  3. 为了Kotlin属性与java反射互操作,KProperty包含3个扩展属性

    • javaField:获取该属性的幕后字段,该属性返回java.lang.reflect.Field对象
    • javaGetter:获取该属性的getter方法,该属性返回java.lang.reflect.Method对象
    • javaSetter:获取该属性的setter方法,该属性返回java.lang.reflect.Method对象

绑定的方法与属性引用

  1. 当函数或属性不在任何类中定义时,程序直接用::函数名或者属性名的形式来获取函数或属性的引用。这些函数或者属性没有绑定任何对象,因此调用函数或属性时第一个参数必须传入调用者

  2. kotlin1.1开始支持绑定的方法与属性引用.方法或属性引用不是通过类获取的而是通过对象获取的。

        //kotlin1.1开始可以通过对象绑定
        val str = "jannal"
        val f: (CharSequence, Boolean) -> Boolean = str::endsWith
        //无需传入调用者
        println(f("1", true))
    
        val prop = str::length
        //无需传入调用者
        println(prop.get())
    
    

获取泛型信息

  1. 在程序运行时,无法得到自己本身的泛型信息(编译擦除,并不总是擦除为 Object类型,而是擦除到上限类型 ),而当这个类继承了一个父类,父类中有泛型的信息时,那么就可以通过调用getGenericSuperclass()方法得到父类 的泛型信息

    class A<T>
    open class C<T>
    class B<T> : C<Int>()
    
    fun test1() {
        // 无法获取运行时T的具体类型,以下运行会报错。
        // 因为java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
        val parameterizedType = A<Int>()::class.java.genericSuperclass as ParameterizedType
        parameterizedType.actualTypeArguments.forEach {
            val typeName = it.typeName
            println("typeName=${typeName}")
        }
    }
    
    fun test2() {
        val parameterizedType = B<Int>()::class.java.genericSuperclass as ParameterizedType
        parameterizedType.actualTypeArguments.forEach {
            val typeName = it.typeName
            //typeName=java.lang.Integer
            println("typeName=${typeName}")
        }
    }
    
    fun main() {
        //test1()
        test2()
    }
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值