前言

标准的Java反射,定义在包 java.lang.reflect 中。因为Kotlin类会被编译成普通的Java字节码,Java反射API可以完美地支持它们。
Kotlin反射API,定义在包kotlin.reflect中。通过Kotlin反射API你可以访问那些在Java世界里不存在的概念,诸如属性和可空类型。Kotlin反射API并不是Java反射API的替代方案。同时,Kotlin反射API没有仅局限于Kotlin类,可以使用同样的API访问用任何JVM语言写的类。

类引用

最基本的反射功能是获取 Kotlin 类的运行时引用。

  1. val daqiKotlinClass = daqiKotlin::class

Kotlin的类引用实际是KClass 类型的值。如果想获取Java类引用,可以在KClass 类实例上使用.java属性获取。

对于Java类引用,可以使用.kotlin将其转换为Kotlin类引用

val daqiKotlinJavaClass = daqiKotlin::class.java
val daqiKotlinaClass = daqiKotlinJavaClass.kotlin

KCallable

在Kotlin的类引用KClass里,属性和函数都是存放在KCallable集合members中,而构造函数存储在KFunction集合constructors中。KFunction的超接口是KCallable,也就是说KCallable是函数(包括构造函数)和属性的超接口。

KCallable中声明了call方法,允许你调用对应的函数或者对应属性的getter:

public actual interface KCallable<out R> : KAnnotatedElement {
    public fun call(vararg args: Any?): R
    .....
}

函数KFunction


在Kotlin中,字节码对应的类是kotlin.reflect.KClass,因为Kotlin百分之百兼容Java,所以Kotlin中可以使用Java中的反射,但是由于Kotlin中字节码.class对应的是KClass类,所以如果想要使用Java中的反射,需要首先获取Class的实例,在Kotlin中可以通过以下两种方式来获取Class实例

 //1.通过类::class的方式获取Kclass实例
val clazz1: KClass<*> = HelloWorld::class
//2.通过实例.javaClass.kotlin获取Kclass实例
var hello = HelloWorld()
val clazz2 = hello.javaClass.kotlin

兼容性

  1. Kotlin的反射兼容java的反射,因为Kotlin类会被编译成普通的Java字节码,Java反射API可以完美地支持它们
  2. Kotlin的反射看起来更简单一些,通过Kotlin反射API你可以访问那些在Java世界里不存在的概念,诸如属性和可空类型。Kotlin反射API并不是Java反射API的替代方案。同时,Kotlin反射API没有仅局限于Kotlin类,可以使用同样的API访问用任何JVM语言写的类

API

kotlin.reflect 包是 Kotlin 反射核心 API,它们都是接口,详细说明如下:

  • KCkass。表示一个具有反射功能的类。
  • KParameter。表示一个具有反射功能的 可传递给函数或属性的参数。
  • KCallable。表示具有反射功能的可调用实例,包括属性和函数,它的直接子接口有 KProperty 和 KFunction。
  • KFunction。表示一个具有反射功能的函数。
  • KProperty。表示一个具有反射功能的属性,它有很多子接口。KProperty0、KProperty1 和 KProperty2 后面的数字表示接收者作为参数的个数。
  • KMutableProperty。表示一个具有反射功能的使用 var 声明的属性。KMutableProperty0、KMutableProperty1 和 KMutableProperty2 后面的数字含义同 KProperty。

KClass和Class

Kotlin是完全兼容java的,同时Kotlin是jvm语言,Kotlin编译之后,会翻译成和java一样的字节码
kotlin语言.png

  • 在Java语言中,class字节码对应的类是Class
  • 在Kotlin语言中,class字节码对应的类是KClass

在虚拟机中只存在一个class文件,他可以封装成Class,也可以封装成KClass,
可以这样理解,KClass和Class是字节码的一体两面,
这也就解释了为什么一个类或者对象,我们可以同时获取KClass,也可以获取Class了

KType和Type的异同

KType的继承关系

KType继承关系.png

Type的继承关系

反射 - 图3

总结

  1. Java中的Class是Type的子类
  2. Kotlin中KClass和KType之间没有继承关系,是平级的,他们都继承自KAnnotatedElement

Why KClass is not a Ktype

KType is more than just a class. In Kotlin, a type can be nullable or not, it can have generic type arguments, and it can be annotated with type annotations. Additionally, a type’s classifier (what the type is “based” on) can be not only a particular class, but a type parameter of some declaration. For example, here:

fun <K : Any, V : Any> get(key: K): V?

K is a type, and V? is a type, and their classifiers are the corresponding type parameters, but the first type is marked as non-null and the second type is nullable.
Generally, KType is something you discover in a function signature and that denotes the set of values that function can take or return. KClass is a concrete class, with a declaration and source somewhere and a fixed fully qualified name, and you can get the (single) class of every instance at runtime.
For your problem, it might be helpful to think what value do the type’s constituents have: should the behavior differ if the type in the function signature is nullable or not? Should generic type arguments be taken into account? Do you have to handle the type annotations in any way? If all answers are no and you also don’t care about types whose classifiers are type parameters, not classes (example above), then you can safely call type.jvmErasure, or type.classifier as KClass<*> to get the KClassinstance.

这个问题还有待继续去理解啊

KAnnotatedElement

Represents an annotated element and allows to obtain its annotations.
这个类很好理解,所有可以使用注解的元素都要实现这个接口,哪些元素可以使用注解呢

  1. 属性字段
  2. 函数
  3. 参数
  4. 还有一些其他的

KCallable

Represents a callable entity, such as a function or a property.

KFunction

Represents a function with introspection capabilities.

KProperty

Represents a property, such as a named val or var declaration. Instances of this class are obtainable by the :: operator.

KProperty与Java的Field不同,它还代表相应的GetterSetter,而Java的Field通常指字段本身。

  • KProperty:代表通用的属性。
  • KMutableProperty:代表通用的读写属性。
  • KProperty0:代表无需调用者的属性。
  • KMutableProperty0:代表无需调用者的读写属性。
  • KProperty1:代表需要1个调用者的属性。
  • KMutableProperty1:代表需要1个调用者的读写属性。
  • KProperty2:代表需要2个调用者的属性。
  • KMutableProperty2:代表需要2个调用者的属性。

image.png

什么叫无需调用者的属性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

val name = "daqi"

fun main(){
    val property = ::name
    property.get()
    property.call()
}

KParameter


Represents a parameter passed to a function or a property getter/setter, including this and extension receiver parameters.

KClass

Represents a class and provides introspection capabilities. Instances of this class are obtainable by the ::class syntax. See the Kotlin language documentation for more information.

KClassifier

A classifier is either a class or a type parameter.

KDeclarationContainer

**Represents an entity which may contain declarations of any other entities, such as a class or a package.

KType

Represents a type. Type is usually either a class with optional type arguments, or a type parameter of some declaration, plus nullability.

image.png

参考

  1. Kotlin中的反射 - 简书