【问题标题】:Creating a new instance of a KClass创建 KClass 的新实例
【发布时间】:2021-08-30 04:57:12
【问题描述】:

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

我有这个类的参考:

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

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

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

kClass.constructors.first().call()

我在 some bug reports 中看到了 primaryConstructor 的提及,但它没有出现在我的 IDE 中。

【问题讨论】:

    标签: reflection kotlin


    【解决方案1】:

    在您的情况下,Java 反射可能就足够了:您可以使用MyClass::class.java 并以与使用 Java 反射相同的方式创建一个新实例(请参阅@IngoKegel 的答案)。

    但如果有多个构造函数并且您确实需要获取主构造函数(不是默认的无参数构造函数),请使用 KClass&lt;T&gt;primaryConstructor 扩展函数。它是Kotlin reflection 的一部分,不在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】:

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

    MyClass::class.java.newInstance()
    

    【讨论】:

    • 真正有趣的是,Kotlin 没有类似的简单和惯用的方式来做到这一点
    • 顺便说一句,Class.newInstance() 自 Java 9 以来已弃用,其参数绕过检查异常。
    • 除非手动创建构造函数,否则这将在数据类上失败
    【解决方案3】:

    对于现在检查这个问题的人来说,从 Kotlin 1.1 开始,KClass 上还有 createInstance() 扩展方法

    与公认的答案非常相似,此函数仅在类具有空构造函数或具有所有默认参数的构造函数的情况下才有效。

    https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect.full/create-instance.html

    【讨论】:

    • 被低估的答案。非常感谢。
    • 我不明白如何使用 createInstance 传递参数。怎么样?
    【解决方案4】:

    扩展 Alexeys 的答案,包括一个带参数的主构造函数调用:

    /* 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
    )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-27
      • 2013-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多