创建一个KClass的新实例

32

我有一个 Kotlin 类,它的主要(也是唯一的)构造函数是空的。

我有一个对这个类的引用:

val kClass: KClass<MyClass> = MyClass::class

如何使用反射创建此类的实例?

在Java中,我会这样做:myClass.newInstance(),但在Kotlin中,似乎需要先找到构造函数:

kClass.constructors.first().call()

我曾在一些错误报告中看到了primaryConstructor的提及,但它并没有出现在我的IDE中。

5个回答

33
在您的情况下,Java反射可能已经足够了:您可以使用MyClass::class.java,并像使用Java反射一样创建一个新实例(请参见@IngoKegel的答案)。
但是,如果有多个构造函数,并且您确实需要获取主要构造函数(而不是默认的无参数构造函数),则可以使用KClass<T>的扩展函数primaryConstructor。它是Kotlin反射的一部分,不包含在kotlin-stdlib中。
要使用它,您必须将kotlin-reflect作为依赖项添加到Gradle项目中,例如:
dependencies {
     compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"    
}

假设有ext.kotlin_version,否则请将$kotlin_version替换为您使用的版本。

然后,您就可以使用primaryConstructor,例如:

fun <T : Any> construct(kClass: KClass<T>): T? {
    val ctor = kClass.primaryConstructor
    return if (ctor != null && ctor.parameters.isEmpty())
        ctor.call() else
        null
}

2
如果构造函数需要参数,上述方法就无用了。 - Tody.Lu
2
如果构造函数需要参数,推荐的方式是什么? - Emily

32

您可以使用Java类创建新实例:

MyClass::class.java.newInstance()

3
很有趣的是,Kotlin没有类似简单和惯用的方法来做到这一点。 - void.pointer
3
顺便提一下,“Class.newInstance()”自Java 9起已被弃用,因为绕过了受检异常的参数。 - Ingo Kegel
1
除非手动创建构造函数,否则这将在数据类上失败。 - Farid

15

2
被低估的答案。非常感谢。 - Danish Ansari
我不明白如何使用传递参数的 createInstance 方法。怎么办? - Luiz Alegria

3

在 Alexey 的回答基础上进行扩展,包括使用参数进行主构造函数调用:

/* Example class with no-args constructor */
class MyClass

/* Example class requiring parameters */
class MyClassWithParams(parameter1: String, parameter2: MyClass)

val myKClass: KClass<MyClass> = MyClass::class
val myKClassWithParameters: KClass<MyClassWithParams> = MyClassWithParams::class

/* We can create an object by calling createInstance when no constructor parameters are required as explained in other answers. */
val myObject: MyClass = myKClass.createInstance()

/* To create an object with parameters, we need to get the constructor first, and call it with the parameters instead, similarly to how we would do in Java. */
val myObjectWithParameters: MyClassWithParams? = 
myKClassWithParameters.primaryConstructor?.call(
    "StringParameter", myObject
)

1
直截了当。感谢分享这个 :) - M.Ed

1

我喜欢hotkey的回答,但我无法使他的primaryConstructor代码示例运行。 我成功运行了以下代码:

    fun <T : Any> construct(kClass: KClass<T>): T? {
      val constructors = kClass.constructors
      for (constructor in constructors) {
           if (constructor.parameters.size == 0) return constructor.call()
      }
      return null;
    }

这个答案是我学习 Kotlin 的早期阶段的一部分。当时我不明白的是,并不是所有的 KClass 都必须有一个 primaryConstructor。这完全取决于你如何定义类,决定了类是否有 primaryConstructor。我曾以为如果你定义一个没有任何构造函数的类,那么没有参数的构造函数就是 primaryConstructor,但事实并非如此。这解释了为什么我无法让 hotkey 的代码正常工作,以及为什么上面的代码在我的情况下能够正常工作。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接