Kotlin学习笔记17 反射Part1

参考链接

示例来自bilibili Kotlin语言深入解析 张龙老师的视频

1 获取Java class和Kotlin KClass的方法

// 获取Java class和Kotlin KClass的方法

fun main() {
    // 获取Kotlin KClass
    val c = String::class
    println(c)
    // 获取Java class
    val c2 = String::class.java
    println(c2)

    println(Int::class)
    println(Int::class.java)

    println(Collection::class)
    println(Collection::class.java)
}

class HelloKotlin1 {
}

2 通过实例(而不是类名) 获取自定义类的Kotlin以及Java 对象

// 通过实例(而不是类名) 获取自定义类的Kotlin以及Java 对象
fun main() {
    val son: Parent = Son()
    val daughter: Parent = Daughter()

    // 注意 因为这里是自定义的class 他们的Java class和Kotlin class输出一样
    println(son::class)
    println(son::class.java)
    println(daughter::class)
    println(daughter::class.java)
}

open class Parent
class Son : Parent()
class Daughter : Parent()

class HelloKotlin2 {
}

3 函数(方法)引用

package com.example.lib.d06reflect

// 函数(方法)引用


// 1 函数引用的普通使用
// 返回一个int的3倍数
fun multiplyBy3(x: Int): Int {
    return x * 3
}

// 2 函数引用的重载
fun multiplyBy3(s: String): Int {
    return s.length
}

fun main() {
    val values = listOf(1, 2, 3) // 返回List 列表

    // val values = arrayOf(1, 2, 3) // 返回Array 数组
    /**
     * Array.map方法的声明
     * public inline fun <T, R> Array<out T>.map(transform: (T) -> R): List<R>
     *     接受一个函数 返回一个一个List
     *     该函数输入一个T类型参数 返回一个R 类型对象 当然 T和R可以相同
     *     map的含义是对集合中的每一个元素施加指定函数
     *
     * 我们可以看到multiplyBy3符合这个函数
     */
    println(values.map(::multiplyBy3)) // 函数类型推断

    val values2 = listOf("hello", "world", "hello world")
    println(values2.map(::multiplyBy3)) // 函数类型推断
}

class HelloKotlin3 {
    fun instanceMethod(s: String): Int {
        return s.length
    }
}

/**
 * 总结
 * 函数引用 
 * 可以传入函数作为参数
 * 函数类型如果能从上下文推断 那么支持重载
 * ::multiplyBy3表示函数类型 (Int)->Int 或者 (String) ->Int的值
 * 如果该方法不是来自顶层的方法 而是某个类的普通方法或者扩展方法 需要加上类的索引
 */
val myRef: (Int) -> Int = ::multiplyBy3
val myRef2: (String) -> Int = ::multiplyBy3
val myRef3: String.(Int) -> Char = String::get
val myRef4: HelloKotlin3.(String) -> Int = HelloKotlin3::instanceMethod // 如果该方法不是来自顶层的方法 而是某个类的普通方法或者扩展方法 需要加上类的索引

4 函数组合

/**
 * 函数组合
 * 将多个函数组合在一起 形成一个函数
 */

/**
 * 该方法接受两个参数 两个参数都是函数类型
 * 返回一个结果 一个结果也是函数类型
 * 接受的参数1 接受类型B 返回类型C
 * 接受的参数2 接受类型A 返回类型B
 * 返回的函数  接受类型A 返回类型C
 *
 * 那么内部调用可以先调用参数2的函数 再调用参数1的函数 正好符合返回的函数的输入输出
 * 有点成语接龙的意思
 * 注意 {}代表lambda表达式 即函数类型
 * 该函数真正的用途是对输入参数依次调用f2 f1 最后输出
 */
fun <A, B, C> myCompose(f1: (B) -> C, f2: (A) -> B): (A) -> C {
    return { x -> f1(f2(x)) }
}

// 三个函数的函数组合
fun <A, B, C, D> myCompose(f0: (C) -> D, f1: (B) -> C, f2: (A) -> B): (A) -> D {
    return { x -> f0(f1(f2(x))) }
}

// 判断一个int是否为偶数 (Int)->Boolean
fun isEven(x: Int) = 0 == x % 2

// 返回字符串长度 (String)->Int
fun length(s: String) = s.length

fun main() {
    // 两个函数组合成一个函数 接受一个String 返回一个Boolean 表示接受参数String的长度如果为偶数则返回true
    val evenLength = myCompose(::isEven, ::length)
    val strings = listOf("1", "12", "123", "1234", "12345")
    // filter方法 接受一个T类型 返回一个Boolean
    println(strings.filter(evenLength))
}

class HelloKotlin4 {
}

5 属性引用

/**
 * 属性引用(Method Reference)
 * 属性引用与之前的函数引用的用法完全一致 通过::属性名 的形式调用
 */

// 1 常量的属性引用
val age = 3

// 2 变量的属性引用 注意是var 不是val
var age2 = 5


fun main() {

    // 首先我们需要了解一个继承结构 KProperty0继承自KProperty KProperty继承自KCallable
    // KClass和KProperty有点像 只不过KClass是Kotlin对应Java的Class  KProperty基本是Kotlin对应Java的Field
    /**
     * ::age代表类型KProperty<Int>的属性对象实例 我们可以通过get()获取其值 通过name获取其名字
     * KProperty:Represents a property, such as a named val or var declaration. Instances of this class are obtainable by the :: operator.
     * KProperty是一个接口 KProperty代表属性 例如val或var的声明 KProperty的class实例可以通过::操作符获取
     * ::age就是获取到了一个KProperty<Int>的实例
     */
    println(::age)
    /**
     * get方法返回KProperty0类型的实例 它是一个接口
     * Represents a property without any kind of receiver. Such property is either originally declared in a receiverless context such as a package, or has the receiver bound to it.
     * KProperty0代表一个没有任何接收者的属性. 这种属性定义在一个无接收者的上下文(例如package内) 或者没有被一个接收者接收者绑定
     * 定义在package内也就是定义在顶层空间的意思 没有绑定到接收者可以反过来理解 String::length就是绑定到了String上 String是接受者
     * 没有绑定到接收者就是::前面没有东西
     *
     */
    println(::age.get())
    /**
     * The name of this callable as it was declared in the source code. If the callable has no name, a special invented name is created. Nameless callables include:
     * constructors have the name "",
     * property accessors: the getter for a property named "foo" will have the name "<get-foo>", the setter, similarly, will have the name "<set-foo>".
     * name属性是KCallable接口的一个属性 他代表源码中定义的名字 如果可调用项没有名称,则会创建一个特殊的虚构名称。匿名可调用项包括:
     * 1.构造函数的名称为""
     * 2.属性访问器:名为foo的属性的getter名称为“<get foo>”,setter将具有名称“<set foo>”(Kotlin中不需要自己定义属性的get set方法 这里解释的应该就是set get方法的name)
     *
     * 这里我们可以先只关注普通的name
     */
    println(::age.name)
    println("========1 end========")

    /**
     * ::age2 返回的类型是KMutableProperty<Int> 它有一个set方法
     * 理解了KProperty后 KMutableProperty其实是类似的
     */
    println(::age2)

    // 通过反射调用set get方法
    ::age2.set(10)
    println(::age2.get())

    // 正常调用set get方法
    age2 = 20
    println(age2)
}

class HelloKotlin5 {
}

6 属性引用作为方法使用

/**
 * 属性引用作为方法使用
 */
fun main() {
    // 1 属性引用作为方法使用
    val values = listOf("a", "ab", "abc")
    /**
     * 这里为什么可以使用属性引用?
     * map接受一个函数作为参数
     * (T) -> R: 接受T 返回R
     * 这里可以理解为 接受每一个item的字符串String 返回 String的length
     *
     * 也就是说属性引用可以用在不接受参数的方法上
     */
    println(values.map(String::length))
    println("=======1 end========")

    // 要想访问一个类中的成员属性 (有接收者的属性)
    // 需要使用全限定名称(需要加上具体类名 如这里的MyClass)
    val x = MyClass::x
    println(x.get(MyClass(10)))
    println(x.get(MyClass()))
}

// 2 有接收者的属性引用
class MyClass(val x: Int = 2)

class HelloKotlin6 {
}

7 属性引用与扩展属性

/**
 * 属性引用与扩展属性
 */
// 给String增加一个扩展属性firstChar
val String.firstChar: Char
    get() = this[0]

fun main() {
    // 正常调用扩展属性
    println("abc".firstChar)

    // 通过属性引用调用扩展属性
    val x = String::firstChar
    println(x.get("abc"))
}

class HelloKotlin7 {
}

8 获取KClass Class等对象的对比示例

// 获取KClass Class等对象的对比示例

class T(var x: Int)

fun main() {
    // Kotlin语境下 获取Java get set的表示
    println(T::x.javaGetter)
    println(T::x.javaSetter)
    // javaClass与javaClass.kotlin的toString可能相同 如下面2个
    // 获取Java类
    println(T(10).javaClass)
    // 获取Java类对应的Kotlin类
    println(T(10).javaClass.kotlin)
    println("------1-----")

    // javaClass与javaClass.kotlin的toString也可能不相同 如下面2个就是不同的
//     val values5:Class<String.Companion> = String.javaClass
//     val values55:KClass<String.Companion> = String.javaClass.kotlin
//    println(values5)
//    println(values55)

    // .javaClass: Returns the runtime Java class of this object.
    val values1: Class<String.Companion> = String.javaClass
    val values11 = "AAA".javaClass
    println(values1)
    println(values11)
    println("------2-----")
    // .kotlin: Returns a KClass instance corresponding to the given Java Class instance.
    val values2: KClass<String.Companion> = String.javaClass.kotlin
    val values22 = "AAA".javaClass.kotlin
    println(values2)
    println(values22)
    println("------3-----")

    // ::class: 返回Kotlin class(KClass)
    // ::代表引用 如果前面跟了类 则是类引用
    // 如果后面跟了属性 则是属性引用
    // 如果后面跟了方法 则是方法引用
    // 实例的引用和类的引用几乎一致
    val values3: KClass<String> = String::class
    val values33: KClass<out String> = "AAA"::class
    println(values3)
    println(values33)
    println("------4-----")
    // .java: Returns a Java Class instance corresponding to the given KClass instance.
    val values4: Class<String> = String::class.java
    val values44 = "AAA"::class.java
    println(values4)
    println(values44)
    println("------5-----")

    // 对比示例 示例来自 https://blog.csdn.net/a568478312/article/details/80718028
    val person = Person()
    val a: KClass<Person> = Person::class
    val b: KClass<out Person> = person::class
    val c: Class<Person> = Person::class.java
    val d: Class<out Person> = person::class.java

    val e: KProperty1<Person, Class<Person>> = Person::javaClass
    val f: KProperty0<Class<Person>> = person::javaClass

    val g: Class<Person.Companion> = Person.javaClass
    val h: Class<Person> = person.javaClass
    val i: KClass<Person.Companion> = Person.javaClass.kotlin
    val j: KClass<Person> = person.javaClass.kotlin
    println(a)
    println(b)
    println(c)
    println(d)
    println(e)
    println(f)
    println(g)
    println(h)
    println(i)
    println(j)
    println("===========================")

    val string = "String"
    val a1: KClass<String> = String::class
    val b1: KClass<out String> = string::class
    val c1: Class<String> = String::class.java
    val d1: Class<out String> = string::class.java

    val e1: KProperty1<String, Class<String>> = String::javaClass
    val f1: KProperty0<Class<String>> = string::javaClass

    val g1: Class<String.Companion> = String.javaClass
    val h1: Class<String> = string.javaClass
    val i1: KClass<String.Companion> = String.javaClass.kotlin
    val j1: KClass<String> = string.javaClass.kotlin
    println(a1)
    println(b1)
    println(c1)
    println(d1)
    println(e1)
    println(f1)
    println(g1)
    println(h1)
    println(i1)
    println(j1)
    val output = """
        class com.example.lib.d06reflect.Person
        class com.example.lib.d06reflect.Person
        class com.example.lib.d06reflect.Person
        class com.example.lib.d06reflect.Person
        val T.javaClass: java.lang.Class<T>
        val T.javaClass: java.lang.Class<T>
        class com.example.lib.d06reflect.Person        ${'$'}Companion
        class com.example.lib.d06reflect.Person
        class com.example.lib.d06reflect.Person        ${'$'}Companion
        class com.example.lib.d06reflect.Person
        ===========================
        class kotlin.String
        class kotlin.String
        class java.lang.String
        class java.lang.String
        val T.javaClass: java.lang.Class<T>
        val T.javaClass: java.lang.Class<T>
        class kotlin.jvm.internal.StringCompanionObject
        class java.lang.String
        class kotlin.String        ${'$'}Companion
        class kotlin.String

        Process finished with exit code 0

    """.trimIndent()
}

class Person {
    var name: String = ""
    var age: Int = 0

    companion object {

    }
}

class HelloKotlin8 {
}

9 使用构造方法的引用(Constructor Reference)

/**
 * 使用构造方法的引用(Constructor Reference)
 *
 * 要使用构造方法的引用 有如下要求
 * 1 函数对象的参数与构造方法的参数一致(包括参数个数 顺序 类型)
 * 2 函数返回对象类型与构造方法创建类型一致
 */

class B(val x: Int)

fun myMethod(factory: (x: Int) -> B) {
    val b: B = factory(3)
    println(b.x)
}

fun main() {
    // 使用构造方法的引用
    myMethod(::B)
}

class HelloKotlin9 {
}

10 获取特定对象实例的属性和方法

/**
 * 获取特定对象实例的属性和方法
 */

fun main() {
    // 通过特定对象实例 获取该实例的实例方法
    val str = "abc"
    val getReference = str::get
    println(getReference(1))

    // 通过特定对象实例 获取该实例的属性
    val myProp="test"::length
    println(myProp.get())

    // 通过Class(而非实例) 获取该类型的属性 但是使用时还是需要传入特定的实例对象
    val myProp2=String::length
    println(myProp2.get("test"))
    // 通过Class(而非实例) 获取该类型的方法 但是使用时还是需要传入特定的实例对象
    val getReference2 = String::get
    // 第一个参数是实例对象 第二个参数是实例方法的参数
    println(getReference2("abc",1))
}

class HelloKotlin10 {
}

11 Java反射和Kotlin反射各种对应关系

import kotlin.reflect.KClass

/**
 * Java反射和Kotlin反射各种对应关系
 *
 * Java   Kotlin
 * Class  KClass
 * Method KFunction
 * Field  KProperty
 * 当然 并不是完全等价 例如与KProperty类似的还有KMutableProperty KProperty0 KMutableProperty0等等
 */

fun main() {
    val kotlinLang = "kotlin"
    val kClass: KClass<out String> = kotlinLang::class // 无论一个类有多少实例 他们的KClass是唯一的 都相等
    println(kClass)

    val kClassDataType: KClass<String> = String::class
    println(kClassDataType)

    val kClass1: KClass<out String> = "kotlin"::class
    val kClass2: KClass<out String> = "java"::class
    val kClass3: KClass<out String> = "ruby"::class
    println(kClass1)
    println(kClass2)
    println(kClass3)
    println(kClass1 == kClass2 && kClass2 == kClass3 && kClass1 == String::class)

    // Java Class 对象
    val javaClass: Class<*> = Class.forName("java.util.Date")
    // Kotlin KClass 对象
    val kClass4: KClass<out Any> = Class.forName("java.util.Date").kotlin
    println(javaClass)
    println(kClass4)
    // 输出一样但是类型不一样会返回false
    println(kClass4 == javaClass)
}

class HelloKotlin11 {
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值