Kotlinで型パラメータの型情報を取得する

フレームワークやライブラリの仕様で、Classインスタンスが必要になる場合があります。
例: AndroidIntentを作る場合、jsonを特定の型にパースする場合など

JavaとKotlinではこのような場合にどのような違いがあるのか調べました。

Javaの場合

以下のようにAndroidIntentを作る際にActivityClassを渡す場合

public <T> void startActivity(Context context, Class<T> clazz) {
    context.startActivity(new Intent(context, clazz));
}

startActivity(this, MainActivity.class)

上のコードは問題なく動きますがジェネリクスで型が分かっているのに引数でClassを渡しているのは冗長な気がします。 型パラメータからClassを取得しようとするとどうなるのでしょうか

public <T> void startActivity(Context context) {
    context.startActivity(new Intent(context, T.class));
}

これはコンパイルエラーになります。これ以外の構文でもTからClassを取得することはできません。
よってJavaでは型パラメータからClassを取得することは基本的にはできず、引数としてClassを渡さなければいけないのです。

Kotlinの場合

Kotlinの場合ではどうでしょうか?

Kotlinでは多少制約はありますが型パラメータのメソッド呼び出しやフィールドアクセスが可能です。
上のJavaコードをKotlinで書くと以下のようになります。

inline fun <reified T> startActivity(context: Context) {
    context.startActivity(Intent(context, T::class.java))
}

startActivity<MainActivity>(this)

ポイントは

  • inline関数にする必要がある
  • 型パラメータにreifiedをつける
  • 型引数に Nothingや、List<String>のように型パラメータ付きのクラス(Arrayは除く)は使えない。

また、obj is Tのように型チェックも可能です。これもJavaではできないです。

最後に

今回はreifiedの機能や使い方について調べてみました。
reifiedを使うには制約がありますが、それは何故なのかも調べてみたいと思います。