热衷于通过 Kotlin Reflection API 获取无参数构造函数?

Hot to get the parameterless constructor through Kotlin Reflection API?

给定一个具有无参数构造函数的域 class,我们如何通过反射获得对该构造函数的引用 API?

例如考虑一个Student数据class,如:

data class Student(var nr: Int = 0, var name: String? = null)

注意,我们可以通过javap确认无参数构造函数的存在,显示:

public pt.isel.Student(int, java.lang.String);
    descriptor: (ILjava/lang/String;)V

public pt.isel.Student(int, java.lang.String, int, kotlin.jvm.internal.DefaultConstructorMarker);
    descriptor: (ILjava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V

public pt.isel.Student();
    descriptor: ()V

然而,none 以下方法 returns 无参数构造函数:

val constructor = Student::class.primaryConstructor
// java.util.NoSuchElementException: Collection contains no element matching the predicate
val constructor = Student::class.constructors.first { it.parameters.isEmpty() }

或者,我们可以通过 Java 反射进行,效果很好,但没有必要这样绕路:

val constructor = Student::class.java.getDeclaredConstructor()

其次,我们为什么需要它?因为我们要在运行时实例化一个域class。是的,我们知道 createInstance() of KClass 可以完成这项工作。但如果没有无参数构造函数,它会抛出 IllegalArgumentException: Class should have a single no-arg constructor

因此,我们想事先检查一下我们是否可以毫无例外地调用 createInstance()

这里的无参数构造函数只存在于编译后的Javaclass,而不存在于你的Kotlin代码中。就 Kotlin 代码而言,您的 Student class 只有一个构造函数,带有 2 个可选参数。

Kotlin反射API被设计为platform-independent,所以必须使用Java反射来获取参数构造函数

如果你只是想看看你是否可以安全地调用 createInstance,你可以只检查 class 是否有一个构造函数,其参数都是可选的。这是 documented:

Creates a new instance of the class, calling a constructor which either has no parameters or all parameters of which are optional. If there are no or many such constructors, an exception is thrown.

val isSafe = someClass.constructors.singleOrNull { 
    it.parameters.all(KParameter::isOptional) 
 } != null

这类似于 createInstance 是如何 implemented 抛出异常。