キーワードの目的を理解しようとしていますreified
。どうやら、ジェネリックのリフレクションが可能になります。
ただし、これを省略しても、同様に動作します。これが実際に違いを生むのはいつでしょうか?
ベストアンサー1
TL;DR: 何reified
に良いのか
fun <T> myGenericFun(c: Class<T>)
のようなジェネリック関数の本体では、型はコンパイル時にのみ利用可能であるため、myGenericFun
型にアクセスすることはできませんが、T
消去された実行時に、ジェネリック型を関数本体で通常のクラスとして使用する場合は、に示すように、クラスをパラメータとして明示的に渡すmyGenericFun
必要があります。
具体化されたinline
を持つ関数を作成すると、 の型は実行時にもアクセスできるため、 を追加で渡す必要はありません。 を通常のクラスであるかのように操作できます。たとえば、変数がのインスタンスであるかどうかを確認したい場合、次のように簡単に実行できます。 T
T
Class<T>
T
T
myVar is T
型inline
を持つこのような関数は次のようになります。reified
T
inline fun <reified T> myGenericFun()
仕組みreified
reified
は関数と組み合わせてのみ使用できますinline
。これにより、関数のバイトコードを関数が呼び出されるすべての場所にコピーするようにコンパイラに指示します (コンパイラは関数を「インライン化」します)。型inline
を使用して関数を呼び出す場合reified
、コンパイラは、生成されたバイトコードを変更して対応するクラスを直接使用できるように、型引数として渡される実際の型を認識できる必要があります。したがって、 のような呼び出しは、バイトコードではmyVar is T
になりますmyVar is String
(型引数が の場合String
)。
例
がいかに役立つかを示す例を見てみましょう。JSON文字列を関数のジェネリック型で指定された型のプレーンKotlinオブジェクトに変換する、calledreified
の拡張関数を作成します。次のように使用できます。String
toKotlinObject
T
com.fasterxml.jackson.module.kotlin
このための最初のアプローチは次のとおりです。
a) 具体化された型を使用しない最初のアプローチ
fun <T> String.toKotlinObject(): T {
val mapper = jacksonObjectMapper()
//does not compile!
return mapper.readValue(this, T::class.java)
}
メソッドreadValue
は、 を解析するはずの型を受け取ります。型パラメータ の をJsonObject
取得しようとすると、コンパイラは「'T' を具体化された型パラメータとして使用できません。代わりにクラスを使用してください。」というエラーを出力します。Class
T
b) 明示的なClass
パラメータによる回避策
fun <T: Any> String.toKotlinObject(c: KClass<T>): T {
val mapper = jacksonObjectMapper()
return mapper.readValue(this, c.java)
}
回避策として、 をClass
メソッドT
パラメータにして、 の引数として使用することができますreadValue
。これは機能し、汎用 Java コードでは一般的なパターンです。次のように呼び出すことができます。
data class MyJsonType(val name: String)
val json = """{"name":"example"}"""
json.toKotlinObject(MyJsonType::class)
c) Kotlin の方法:reified
型パラメータinline
を持つ関数を使用すると、関数を異なる方法で実装できるようになります。reified
T
inline fun <reified T: Any> String.toKotlinObject(): T {
val mapper = jacksonObjectMapper()
return mapper.readValue(this, T::class.java)
}
Class
追加の を取る必要はなくT
、T
通常のクラスと同じように使用できます。クライアントの場合、コードは次のようになります。
json.toKotlinObject<MyJsonType>()
重要な注意: Java の使用
reified
型を持つインライン関数は、Javaコードから呼び出すことができません。