1. 概要

このチュートリアルでは、リフレクションとKClassトークンを使用してKotlinオブジェクトをインスタンス化するいくつかの方法を列挙します。

2. 依存関係

この記事では、kotlin-reflectモジュールをかなり広範囲に使用します。 したがって、その依存関係をpom.xmlなどのビルドファイルに追加する必要があります。

<dependency>
    <groupId>org.jetbrains.kotlin</groupId>
    <artifactId>kotlin-reflect</artifactId>
    <version>1.5.21</version>
</dependency>

さらに、 KClass トークンを操作するには、次の3つのクラスを使用します。

class NoArg
class OptionalArgs(val arg: String = "default")
class RequiredArgs(val arg1: String, val arg2: String) {
    constructor(arg1: String): this(arg1, "default")
}

最初のコンストラクターには引数なしのコンストラクターがあり、2番目のコンストラクターは1つのオプションのパラメーターのみを受け入れ、最後のコンストラクターには2つの必須パラメーターが必要です。 これらに加えて、最後のクラスには2次コンストラクターもあります。

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)

ただし、コンストラクターにコンストラクター引数が必要なクラスをインスタンス化しようとすると、例外がスローされます。

val exception = assertThrows<IllegalArgumentException> { RequiredArgs::class.createInstance() }
assertThat(exception).hasMessageStartingWith("Class should have a single no-arg constructor")

上に示したように、プライマリコンストラクターには2つの必須パラメーターがあるため、IllegalArgumentExceptionのインスタンスがスローされます。

3.1. プライマリコンストラクタ

少なくとも1つの必須コンストラクター引数を持つクラスのインスタンスを作成するために、プライマリコンストラクターを反射的に呼び出すことができます

val primaryConstructor = RequiredArgs::class.primaryConstructor
val instance = primaryConstructor!!.call("first arg", "second arg")
assertNotNull(instance)
assertThat(instance).isInstanceOf(RequiredArgs::class.java)

ここで、 primaryConstructorextensionプロパティはプライマリコンストラクターを検索します。 さらに、 call()関数は、指定された引数を使用して指定されたコンストラクターを実行します。

3.2. 二次コンストラクタ

複数のコンストラクターがある場合、コンストラクター拡張プロパティを使用して、適切なコンストラクターを見つけることができます。

val constructors = RequiredArgs::class.constructors
val instance = constructors.first { it.parameters.size == 1 }.call("arg1")
assertEquals("arg1", instance.arg1)
assertEquals("default", instance.arg2)

ここでは、引数が1つだけのコンストラクターを見つけるためにフィルタリングしています。

4. 結論

この記事では、KClassトークンを指定してKotlinオブジェクトをインスタンス化するいくつかの方法について説明しました。

いつものように、すべての例はGitHubから入手できます。