1前書き

リフレクションは、実行時にクラス、フィールド、およびメソッドを検査、ロード、および対話する機能の名前です。コンパイル時にそれらが何であるかわからない場合でも、これを実行できます。

私たちが開発しているものによっては、これには多くの用途があります。

例えば、Springのようなフレームワークはそれを多用しています。

これに対するサポートはJVMに組み込まれているため、すべてのJVMベースの言語で暗黙的に利用可能です。ただし、一部のJVM言語では、すでに使用可能になっているものに加えて追加のサポートがあります。


2 Javaリフレクション

  • 標準のhttps://www.baeldung.com/java-reflection[Java Reflection]構成要素はすべて利用可能で、Kotlinコードと完全に連携しています。これには、

    java.lang.Class

    クラスと、

    java.lang.reflect

    パッケージ内のすべてのものが含まれます。

何らかの理由で標準のJava Reflection APIを使用したい場合は、Javaの場合とまったく同じ方法で使用できます。たとえば、Kotlinクラスのすべてのパブリックメソッドのリストを取得するには、次のようにします。

MyClass::class.java.methods

これは、次の構成要素に分類されます。


  • MyClass :: class

    は、Kotlinクラスの表現を


MyClass

クラス
**

.java

は、

java.lang.Class

に相当するものを提供します。


  • .methods

    は、

    java.lang.Class.getMethods()

    アクセサへの呼び出しです。

方法

  • これは、JavaまたはKotlinのどちらから呼び出された場合でも、JavaクラスまたはKotlinクラスのどちらから呼び出された場合でもまったく同じように機能します。これには、データクラスなどのKotlin固有のコンストラクトが含まれます。

data class ExampleDataClass(
  val name: String, var enabled: Boolean)

ExampleDataClass::class.java.methods.forEach(::println)

Kotlinは返された型をKotlin表現にも変換します。

上記では、

forEach()を呼び出すことができる

kotlin.Array <Method> __が得られます。


3 Kotlin Reflectionの機能強化

  • 標準のJava Reflection APIを使用することはできますが、Kotlinによってプラットフォームにもたらされるすべての拡張機能については認識されていません** 。

さらに、状況によっては使用するのが少し面倒なこともあります。 Kotlinは、これらの問題を解決するために私たちが使用できる独自のリフレクションAPIを持っています。

Kotlin Reflection APIへのすべてのエントリポイントは参照を使用します。先ほど、Class定義への参照を与えるために__

class__を使用しました。これを使ってメソッドやプロパティへの参照を取得することもできます。


3.1. コトリンクラスの参照

  • Kotlin Reflection APIはクラス参照へのアクセスを許可します。これは、Kotlinクラス** の詳細を詳しく調べるために使うことができます。これにより、Javaクラス参照(

    java.lang.Class

    オブジェクト)へのアクセスが可能になりますが、Kotlin固有の詳細すべてにもアクセスできます。

    クラス詳細用のKotlin APIは、

    kotlin.reflect.KClass

    クラスを中心にしています。 ** これは、任意のクラス名またはインスタンスから__


    演算子を使用してアクセスできます。

    String :: class.__

あるいは、Javaの

Class

インスタンスが利用可能な場合は、拡張メソッド

java.lang.Class.kotlin

を使用してアクセスできます。

val listClass: KClass<List> = List::class

val name = "Baeldung"
val stringClass: KClass<String> = name::class

val someClass: Class<MyType>
val kotlinClass: KClass<MyType> = someClass.kotlin


  • KClass

    オブジェクトを取得したら、それが問題のクラスについて教えてくれる簡単なことがあります** 。これらのいくつかは標準的なJavaの概念であり、他はKotlin特有の概念です。

たとえば、クラスが抽象クラスか最終クラスかは簡単にわかりますが、クラスがデータクラスかコンパニオンクラスかを調べることもできます。

val stringClass = String::class
assertEquals("kotlin.String", stringClass.qualifiedName)
assertFalse(stringClass.isData)
assertFalse(stringClass.isCompanion)
assertFalse(stringClass.isAbstract)
assertTrue(stringClass.isFinal)
assertFalse(stringClass.isSealed)

クラス階層を移動する方法もあります。 Javaでは、クラスからそのスーパークラス、インターフェース、そしてそのクラスに囲まれた外部クラスへ、すでに移行することができます – 必要に応じて。

Kotlinはこれに任意のクラスのためのCompanionオブジェクトとObjectクラスのための

Object

インスタンスを取得する機能を追加します。

println(TestWithCompanion::class.companionObject)
println(TestWithCompanion::class.companionObjectInstance)
println(TestObject::class.objectInstance)

  • Javaと同じ方法で、クラス参照からクラスの新しいインスタンスを作成することもできます。

val listClass = ArrayList::class

val list = listClass.createInstance()
assertTrue(list is ArrayList)

あるいは、コンストラクタにアクセスし、必要に応じて明示的なコンストラクタを使用することもできます。次のセクションで説明するように、これらはすべてメソッド参照です。

非常によく似た方法で、クラスのすべてのメソッド、プロパティ、拡張機能、その他のメンバーにアクセスできます。

val bigDecimalClass = BigDecimal::class

println(bigDecimalClass.constructors)
println(bigDecimalClass.functions)
println(bigDecimalClass.memberProperties)
println(bigDecimalClass.memberExtensionFunctions)


3.2. コトリン法の参考文献

クラスと対話できることに加えて、

メソッドとプロパティ

とも対話できます。

これには、

val

または

var

で定義されたクラスプロパティ、標準クラスメソッド、および最上位関数が含まれます。これまでと同様に、これは標準のJavaで書かれたコードでもKotlinで書かれたコードでも同じようにうまく機能します。

クラスとまったく同じ方法で、


__

__演算子** を使ってMethodまたはPropertyへの参照を取得できます。

これは、メソッド参照を取得するためのJava 8とまったく同じに見えますが、これをまったく同じ方法で使用できます。ただし、Kotlinでは、このメソッド参照を使用してターゲットに関する反射情報を取得することもできます。

  • メソッド参照を取得したら、それが実際に問題のメソッドであるかのように呼び出すことができます** 。これは呼び出し可能参照として知られています。

val str = "Hello"
val lengthMethod = str::length

assertEquals(5, lengthMethod())

クラスの場合と同じ方法で、メソッド自体に関する詳細を取得することもできます。これには、標準のJavaの詳細と、メソッドが

operator

の場合や__inlineの場合など、Kotlin固有の詳細の両方が含まれます。

val byteInputStream = String::byteInputStream
assertEquals("byteInputStream", byteInputStream.name)
assertFalse(byteInputStream.isSuspend)
assertFalse(byteInputStream.isExternal)
assertTrue(byteInputStream.isInline)
assertFalse(byteInputStream.isOperator)

  • これに加えて、この参照を通じてメソッドの入力と出力に関するより多くの情報を得ることができます** 。

これには、null値の可能性やオプションなど、Kotlin固有の詳細情報を含む、戻り値の型とパラメータに関する詳細情報が含まれます。

val str = "Hello"
val method = str::byteInputStream

assertEquals(
  ByteArrayInputStream::class.starProjectedType,
  method.returnType)
assertFalse(method.returnType.isMarkedNullable)

assertEquals(1, method.parameters.size)
assertTrue(method.parameters[0].isOptional)
assertFalse(method.parameters[0].isVararg)
assertEquals(
  Charset::class.starProjectedType,
  method.parameters[0].type)


3.3. Kotlinプロパティ参照

  • これは、プロパティでもまったく同じように機能します。** 明らかに、取得できる詳細は異なります。代わりにプロパティは、それらが定数であるのか、遅い初期化されているのか、または可変であるのかを知らせてくれます。

lateinit var mutableProperty: String
val mProperty = this::mutableProperty
assertEquals("mutableProperty", mProperty.name)
assertTrue(mProperty.isLateinit)
assertFalse(mProperty.isConst)
assertTrue(mProperty is KMutableProperty<** >)

  • Propertiesの概念は、Kotlin以外のコードでも機能することに注意してください。

これらは、getterおよびsetterメソッド** に関するJavaBeansの規約に従ったフィールドによって識別されます。

これには、Java標準ライブラリのクラスが含まれます。たとえば、

Throwable

クラスには

getMessage()

メソッドが定義されているという事実から、

Throwable

クラスにはProperty

Throwable.message

があります。

  • 公開されているメソッド参照を通じて、実際のP​​ropertyにアクセスできます** –

    getter

    および

    setter

    メソッド。

    setter

    は、

    KMutablePropertyを使用している場合にのみ使用可能です。つまり、プロパティは

    var

    として宣言されていましたが、

    getter__は常に使用可能です。

これらは

get()

および

set()

メソッドを介してより使いやすい方法で公開されています。

getter



setter

の値は実際のメソッド参照なので、他のメソッド参照とまったく同じように扱うことができます。

val prop = this::mutableProperty

assertEquals(
  String::class.starProjectedType,
  prop.getter.returnType)

prop.set("Hello")
assertEquals("Hello", prop.get())

prop.setter("World")
assertEquals("World", prop.getter())


4概要

この記事では、Kotlinでリフレクションを使用することで実現できることのいくつかの概要を説明します。これには、標準のJava言語に組み込まれているリフレクション機能との相互作用および相違点も含まれます。

すべての例はhttps://github.com/eugenp/tutorials/tree/master/core-kotlin[GitHubで利用可能]にあります。