1. 概述
在本教程中,我们将介绍几种通过反射和 KClass
类型令牌来创建 Kotlin 类实例的方法。这在某些需要动态实例化的场景下非常有用,比如依赖注入、序列化/反序列化等。
我们将会用到 Kotlin 的反射模块 kotlin-reflect
,并演示如何处理不同类型的构造函数:无参构造函数、含可选参数的构造函数、以及含必填参数的构造函数。
2. 依赖配置
为了使用 KClass
和反射功能,我们需要引入 kotlin-reflect
模块。如果你使用 Maven 构建项目,可以在 pom.xml
中添加如下依赖:
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
<version>1.5.21</version>
</dependency>
我们还会用到以下三个用于测试的类:
class NoArg
class OptionalArgs(val arg: String = "default")
class RequiredArgs(val arg1: String, val arg2: String) {
constructor(arg1: String): this(arg1, "default")
}
其中:
NoArg
类有一个无参构造函数 ✅OptionalArgs
有一个带默认值的可选参数 ❗️RequiredArgs
有两个必填参数,并且还有一个只带一个参数的次级构造函数 ⚠️
3. 反射创建实例
从 Kotlin 1.1 开始,KClass
提供了一个扩展方法 createInstance()
,可以用于通过反射创建类的实例:
val noArgInstance = NoArg::class.createInstance()
assertNotNull(noArgInstance)
assertThat(noArgInstance).isInstanceOf(NoArg::class.java)
✅ 该方法仅适用于无参构造函数或所有参数都有默认值的构造函数。因此,也可以用于 OptionalArgs
:
val instance = OptionalArgs::class.createInstance()
assertNotNull(instance)
assertThat(instance).isInstanceOf(OptionalArgs::class.java)
❌ 但如果尝试用它来创建含有必填构造参数的类(如 RequiredArgs
),就会抛出异常:
val exception = assertThrows<IllegalArgumentException> { RequiredArgs::class.createInstance() }
assertThat(exception).hasMessageStartingWith("Class should have a single no-arg constructor")
这是因为 createInstance()
要求类必须有无参构造函数。否则就会抛出 IllegalArgumentException
。
3.1 使用主构造函数
对于有必填参数的类,我们可以直接获取其主构造函数并调用它:
val primaryConstructor = RequiredArgs::class.primaryConstructor
val instance = primaryConstructor!!.call("first arg", "second arg")
assertNotNull(instance)
assertThat(instance).isInstanceOf(RequiredArgs::class.java)
primaryConstructor
是一个扩展属性,用来获取类的主构造函数 ✅call()
方法用于执行构造函数并传入参数 ❗️
3.2 使用次级构造函数
当一个类有多个构造函数时,可以通过 constructors
属性获取所有构造函数,并选择合适的那个来调用:
val constructors = RequiredArgs::class.constructors
val instance = constructors.first { it.parameters.size == 1 }.call("arg1")
assertEquals("arg1", instance.arg1)
assertEquals("default", instance.arg2)
上面的例子中我们:
- 获取所有构造函数
- 找到参数个数为 1 的那个
- 调用该构造函数并传入
"arg1"
这样就可以成功调用次级构造函数创建实例。
4. 小结
在本文中,我们学习了如何通过 KClass
反射创建 Kotlin 类的实例,包括:
- ✅ 使用
createInstance()
创建无参或默认参数类的实例 - ✅ 使用
primaryConstructor
和call()
创建主构造函数需要参数的实例 - ✅ 使用
constructors
属性查找并调用合适的次级构造函数
这些方法在动态创建对象、依赖注入框架、插件系统等场景中非常实用。
所有示例代码都可以在 GitHub 仓库 中找到。