oynix

于无声处听惊雷,于无色处见繁花

Kotlin的KClass,Java的Class

Java中有Class,而Kotlin则有它的KClass,说说二者的区别和联系。

1. Java Class

Java中的Class是一个final修饰的类,只有一个私有的构造方法,

1
2
3
4
5
6
7
8
public final class Class<T> {
/*
* Private constructor. Only the Java Virtual Machine creates Class objects.
* This constructor is not used and prevents the default constructor being
* generated.
*/
private Class() {}
}

根据方法说明可以知道,这个构造方法是给JVM调用的,JVM在加载类的时候会创建对应的Class实例,存放在方法区,一个类只会有一个Class实例,所以下面这个例子中,c1和c2是一样的。

1
2
3
4
5
6
// Java
class Person {}

Person p = new Person();
Class c1 = p.getClass();
Class c2 = Person.class;

Class类中的方法和成员变量相当之多,但基本都关于Class本身的数据相关,比如获取成员函数、获取成员变量,等等。

2. Kotlin KClass

与Java Class不同的是,KClass是一个接口,根据接口说明,::class可以获取到KClass的实例,这个接口中同样也是声明了一些和类有关的变量,比如类的名字,类的成员等等

1
2
3
4
5
6
7
8
/**
* Represents a class and provides introspection capabilities.
* Instances of this class are obtainable by the `::class` syntax.
* See the [Kotlin language documentation](https://kotlinlang.org/docs/reference/reflection.html#class-references)
* for more information.
*
* @param T the type of the class.
*/

KClass有一个实现类,名字是ClassReference,根据名字可以看出,这个类就是参考的Class,通过将Class实例作为构造参数传入,相关字段均通过class实例获取

1
public class ClassReference(override val jClass: Class<*>) : KClass

通过Kotlin可扩展的语言自身特性,为KClass扩展了几个属性,这些属性在JvmClassMapping.kt中

1
2
3
4
5
6
7
8
9
10
public val <T> KClass<T>.java: Class<T>
public val <T : Any> Class<T>.kotlin: KClass<T>

public inline val <T : Any> T.javaClass: Class<T>

public val <T : Any> KClass<T>.javaPrimitiveType: Class<T>?
public val <T : Any> KClass<T>.javaObjectType: Class<T>

@Deprecated("Use 'java' property to get Java class corresponding to this Kotlin class or cast this instance to Any if you really want to get the runtime Java class of this implementation of KClass.", ReplaceWith("(this as Any).javaClass"), level = DeprecationLevel.ERROR)
public inline val <T : Any> KClass<T>.javaClass: Class<KClass<T>>

前两个属性还挺有趣,Class.kotlin获取KClass,KClass.javaClass获取Class,真是你中有我,我中有你,.完java再.kotlin,能这么一直循环玩下去。后两个属性的区别是,如果本身不是原始类型,那么javaPrimitiveType会返回null。

最后一个javaClass,已经弃用了,上面写了,让使用java属性,那就不管它就好了

3. 总结

Java的Class我们是很熟识的了,容易造成混乱的,就是它和KClass的关联,二者可以互相获取

  • 获取KClass,按照文档里写的,直接取class属性,在实例和在类上调用,获得的结果是一样的
    1
    2
    3
    4
    5
    6
    7
    // 1. 直接获取
    class Person {}
    val kc1 = Person::class
    val kc2 = Person()::class

    // 2. 从Class获取
    val kClass = Person().javaClass.kotlin
  • 获取Class,主要通过扩展属性
    1
    2
    3
    4
    5
    // 1. 从实例获取
    val jClass = Person().javaClass

    // 2. 从KClass获取
    val jClass = Person::class.java
------------- (完) -------------
  • 本文作者: oynix
  • 本文链接: https://oynix.com/2022/04/cf0bb291ed6f/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

欢迎关注我的其它发布渠道