0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Kotlin】Kotlin の `reified` ジェネリクスとインライン関数

Last updated at Posted at 2025-10-04

はじめに

Kotlin のジェネリクスは JVM の制約により 実行時に型が消える(型消去) 方式ですが、
inlinereified を組み合わせることで 実行時にも型を扱う ことができます。


1. 背景:型消去の問題

通常のジェネリック関数では、実行時に型情報は消えてしまいます。

fun <T> checkType(value: Any) {
    if (value is T) { // ❌ コンパイルエラー
        println("Yes, it's T")
    }
}

⚠️ コンパイルエラー:


Cannot check for instance of erased type 'T (of fun <T> checkType)'.

これは 型パラメータ T が実行時に存在しない(消去される) ためです。
これを解決するのが reified 型パラメータです。


2. reified 型パラメータとは?

reified(リファイド)は「具象化された」という意味。
つまり、「実行時にも型情報を保持する」ことができます。

基本構文

inline fun <reified T> checkType(value: Any) {
    if (value is T) { // ✅ 使える!
        println("This is ${T::class.simpleName}")
    } else {
        println("Not ${T::class.simpleName}")
    }
}

checkType<String>("Hello") // ✅ This is String
checkType<Int>("Hello")    // ❌ Not Int

通常は不可能な is TT::class が、reified によって実行時でも使えるようになります。


3. なぜ inline が必要なのか?

reifiedインライン関数 とセットでしか使えません。
つまり:

inline fun <reified T> foo() { ... } // ✅ OK
fun <reified T> foo() { ... }       // ❌ コンパイルエラー

理由は:

インライン化(inline) によって、呼び出し元に型情報が「埋め込まれる」から。

イメージ図

呼び出し元:
checkType<String>("Hello")

↓ インライン展開後(コンパイル時)

if ("Hello" is String) { ... }

T は消去されず、具体的な String 型として展開されます。
これにより実行時にも型チェックが可能になります。


4. reified でできること

機能 説明
型チェック is T が使える if (value is T)
クラス参照 T::classT::class.java が使える T::class.simpleName
リフレクション T::class.members などを取得可能 Reflection API
JSON パースなどの型推論 TypeToken の代替 Gson/Moshiなど

5. 例:reified を使った JSON デシリアライズ

通常のジェネリクスでは、型情報が消えるため
List<User> のような複雑な型を扱えません。

reified を使えば次のように書けます:

inline fun <reified T> parseJson(json: String): T {
    val type = object : TypeToken<T>() {}.type
    return Gson().fromJson(json, type)
}

data class User(val name: String, val age: Int)

val json = """[{"name":"Alice","age":20},{"name":"Bob","age":25}]"""
val users: List<User> = parseJson(json)
println(users)

reified により List<User> の型情報を実行時に渡せるため、
Gson は正しくデコードできます。


6. reified の応用例

① 型判定を共通化

inline fun <reified T> Any?.isTypeOf(): Boolean = this is T

println("abc".isTypeOf<String>()) // true
println(123.isTypeOf<String>())   // false

② クラスインスタンス生成

inline fun <reified T: Any> createInstance(): T =
    T::class.java.getDeclaredConstructor().newInstance()

val sb = createInstance<StringBuilder>()
sb.append("Hello Reified!")
println(sb.toString())

③ 複数型の分岐処理

inline fun <reified T> printType(value: T) {
    when (T::class) {
        String::class -> println("文字列")
        Int::class -> println("整数")
        else -> println("その他の型")
    }
}

printType("Hi") // 文字列
printType(42)   // 整数

7. reified の制約まとめ

制約 内容
inline 関数でのみ使える コンパイル時展開が必要
型引数の reification は JVM 上でのみ有効 JS/Native では動作が異なる場合あり
実行時リフレクションに強いが、メモリ消費に注意 型情報を保持するためオーバーヘッドあり

まとめ

項目 通常のジェネリクス reified ジェネリクス
実行時型情報 消える(型消去) 残る(具象化)
is T チェック ❌ 不可 ✅ 可能
T::class 参照 ❌ 不可 ✅ 可能
使用制限 制限なし inline 関数内のみ
主な用途 型安全な API 設計 実行時に型を使う処理(JSON, DI など)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?