深入kotlin - KClass 特性深入研究

Posted 颐和园

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入kotlin - KClass 特性深入研究相关的知识,希望对你有一定的参考价值。

KClass 特性深入研究

kotlin 反射 vs. Java 反射

其实可以通过 KClass 获取属性的 java 特性,比如获得 get/set 方法和 field 的引用:

class T(val x:Int)

fun main(args: Array<String>) 
	println(T::x) // 打印:val com.kotlin.T.x: kotlin.Int
  println(T::x.javaGetter) // 打印:public final int com.kotlin.T.getX()
  println(T::x.javaField) // 打印:private final int com.kotlin.T.x

javaGetter 打印的是对应的 java 字节码的 getter 方法 - 即 java 反射中的Method 对象,javaField 打印的是 java 的 back field - 即 java 反射中的 Field。

也可以通过 java 类获得对应的 kotlin 类:

println(T(10).javaClass) // KClass -> Java Class,打印:class com.kotlin.T
println(T(10).javaClass.kotlin) // Java Class -> KClass,打印: class com.kotlin.T

这里二者打印的结果实际上是一样的。这是因为 T 本身就是一个自定义的 kotlin 类,它的 kotlin 类和 java 类是一样的。如果是一个 java 类则打印的结果又会不同:

println(String.javaClass) // 打印:class kotlin.jvm.internal.StringCompanionObject
println(String.javaClass.kotlin) // 打印:class kotlin.String$Companion

StringCompanionObject 和 String$Companion 都是伴生对象。

KClass 的两种引用方式

无论通过类还是实例引用的 KClass,都没有任何区别:

fun main(args: Array<String>) 
	val kotlinLang = "kotlin"
  val kclass: KClass<out String> = kotlinLang::class
  println(kclass) // 打印:class kotlin.String
  
  val kclass1: KClass<String> = String::class
  println(kclass1) // 打印:class kotlin.String

无论类有多少个实例,所有实例都对应唯一的 KClass 对象:

fun main(args: Array<String>) 
	val kc1: KClass<out String> = "kotlin"::class
  val kc2: KClass<out String> = "java"::class
  val kc3: KClass<out String> = "ruby"::class
  
  println(kc1) // 打印:class kotlin.String
  println(kc2) // 打印:class kotlin.String
  println(kc3) // 打印:class kotlin.String
  println( kc1 == kc2) // 打印:true
  println( kc1 == kc3) // 打印:true

从 java 类获取 KClass

从一个 java class 获取 KClass:

val kc = Class.forName("java.util.Date").kotlin
println(kc) // 打印: class java.util.Date
println(kc == Class.forName("java.util.Date")) // 打印:false
println(kc == Class.forName("java.util.Date").kotlin) // 打印:true

可以看到,虽然 KClass 和 java class 的打印结果一样(都是 java.util.Date),但二者实质上仍然是不同的实例。

反射父类

通过 KClass 可以通过 superclasses 反射所有父类/接口的信息:

interface MyInterface
class MyClass: Serializable, MyInterface

fun main(args:Array<String>) 
	val kc = MyClass::class
	println(kc.superclasses) // 打印:[class java.io.Serializable, com.kotlin.MyInterface, class kotlin.Any]

反射成员属性

通过 memberProperties 可以反射成员属性:

class MyClass(var a: String, val b: Boolean)
fun main(args:Array<String>)
	val kc = MyClass::class
	println(kc.memberProperties) // 打印:[var com.kotlin.MyClass.a:kotlin.String, val com.kotlin.MyClass.b:kotlin.Boolean]

反射成员函数
class MyClass 
	fun printSomething()
		println("something")
	
	fun printNothing() 
		println("")
	

fun main(args:Array<String>)
  val kc = MyClass:class
  println(kc.memberFunctions)


反射构造函数
class MyClass(value: Int) 
	constructor(amount: Int, color: String): this(amount) 
		println("次要构造方法")
	
	constructor(amount:Int, full: Boolean): this(amount) 
		println("次要构造方法")
	
	fun printSomething()

fun main(args: Array<String>)
	val kc = MyClass::class
  val constructors = kc.constructors // 获取所有构造方法的 KFunction 对象
  println(constructors) // 打印:[fun <init>(kotlin.Int,kotlin.String): com.kotlin.MyClass, fun <init>(kotlin.Int,kotlin.Boolean):com.kotlin.MyClass, fun <init>(kotlin.Int):com.kotlin.MyClass]  

以上是关于深入kotlin - KClass 特性深入研究的主要内容,如果未能解决你的问题,请参考以下文章

深入kotlin - KClass 特性深入研究

深入kotlin - 方法引用和属性引用

深入kotlin - 方法引用和属性引用

活动推荐BXT技术沙龙报名:深入浅出谈Kotlin

从 Java 角度深入理解 Kotlin

从 Java 角度深入理解 Kotlin