参考链接
示例来自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.youkuaiyun.com/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 {
}