型消去とreified型パラメータ
inline関数でreifiedを使い、実行時に型情報へアクセスします。
「型消去とreified型パラメータ」はCoddyKit上の無料Kotlin Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはKotlin Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Kotlin Academyコースには全4レッスンが含まれています。
型消去とは
実行時、JVMはジェネリック型の型引数を消去します。List<String>もList<Int>も、実際には単なるListです。そのため、ジェネリック型に対する実行時の型操作には制限があります。
fun main() {
val strings: List<String> = listOf("a", "b")
val ints: List<Int> = listOf(1, 2)
println(strings.javaClass == ints.javaClass) // true: both ArrayList
println(strings is List<*>) // OK with star
// println(strings is List<String>) // warning: unchecked cast
}問題:消去された型はチェックできない
実行時には型情報が失われているため、特定のジェネリック型引数に対してisを使用することはできません。
fun checkType(obj: Any) {
// This works:
if (obj is List<*>) println("It's a list of something")
// This doesn't compile cleanly:
// if (obj is List<String>) println("It's a list of strings") // unchecked
}
fun main() {
checkType(listOf("hello"))
checkType(42)
}inline関数の復習
inlineは、コンパイル時に関数本体を呼び出し箇所へコピーします。これによりreifiedが可能になります。型引数も呼び出し箇所で置き換えられるためです。
inline fun <T> myRun(block: () -> T): T = block()
fun main() {
val result = myRun { 42 }
println(result) // 42
// The compiler inlines the lambda body — no object allocation
}reified:実行時のTへのアクセス
inlineとreifiedを組み合わせると、呼び出し箇所で型引数が保持され、Tに対してis、as、::classを使用できるようになります。
inline fun <reified T> isInstance(value: Any): Boolean = value is T
fun main() {
println(isInstance<String>("hello")) // true
println(isInstance<Int>("hello")) // false
println(isInstance<List<*>>(listOf())) // true
}TのKClassを取得する
reified Tを使うと、実行時にT::classを取得できます。通常、ジェネリック関数では不可能な操作です。
inline fun <reified T> classNameOf(): String = T::class.simpleName ?: "Unknown"
fun main() {
println(classNameOf<String>()) // String
println(classNameOf<Int>()) // Int
println(classNameOf<List<*>>()) // List
}reifiedによる安全なキャスト
reifiedを使って、例外をスローする代わりにnullを返す型安全なキャストユーティリティを作成します。
inline fun <reified T> Any?.safeCast(): T? = this as? T
fun main() {
val obj: Any = "Hello"
val s: String? = obj.safeCast<String>()
val i: Int? = obj.safeCast<Int>()
println(s) // Hello
println(i) // null
}reifiedによるJSON解析
Gsonやkotlinx.serializationなどのライブラリは、Classオブジェクトを明示的に渡さなくても、呼び出し箇所でreifiedを使って対象の型を推論します。
import com.google.gson.Gson
// Simulated without real Gson:
inline fun <reified T> parseJson(json: String): T {
return Gson().fromJson(json, T::class.java)
}
// Usage:
// val user: User = parseJson<User>("""{"name":"Alice"}""")filterIsInstanceでのreified
標準ライブラリのfilterIsInstance<T>()はreifiedを使い、手動でキャストせずにリストを特定の型へ絞り込みます。
fun main() {
val mixed: List<Any> = listOf(1, "hello", 2.5, "world", true)
val strings = mixed.filterIsInstance<String>()
val ints = mixed.filterIsInstance<Int>()
println(strings) // [hello, world]
println(ints) // [1]
}inlineでない関数ではreifiedを使用できない
reifiedはinline関数でのみ使用できます。inlineなしで使用しようとするとコンパイルエラーになります。
// Error:
// fun <reified T> broken(): String = T::class.simpleName ?: "?"
// Must be inline:
inline fun <reified T> correct(): String = T::class.simpleName ?: "?"
fun main() {
println(correct<Double>()) // Double
}reifiedとリフレクション
reifiedとリフレクションを組み合わせると、定型的なClassパラメーターを使わずに、型のプロパティやアノテーションを動的に調べられます。
inline fun <reified T : Any> properties(): List<String> =
T::class.members.map { it.name }
data class Point(val x: Int, val y: Int)
fun main() {
println(properties<Point>()) // [x, y, component1, component2, copy, equals, hashCode, toString]
}実践:型安全なサービスロケーター
reifiedを使って、KClassとインスタンスを対応付けるサービスロケーターを構築します。アノテーションプロセッサーを使わない軽量なDIに利用できます。
val registry = mutableMapOf<kotlin.reflect.KClass<*>, Any>()
inline fun <reified T : Any> register(instance: T) { registry[T::class] = instance }
@Suppress("UNCHECKED_CAST")
inline fun <reified T : Any> resolve(): T = registry[T::class] as T
class Logger { fun log(msg: String) = println("[LOG] $msg") }
fun main() {
register(Logger())
resolve<Logger>().log("Service located!")
}reifiedの制限
reified型パラメーターは、inlineでないコンテキストでは使用できません。また、型を後で使用するために保存したり、実行時に型を必要とするinlineでない関数へ渡したりすることもできません。
inline fun <reified T> foo() {
val clazz = T::class // OK here
// bar(clazz) // must pass clazz explicitly to non-inline funs
println(clazz.simpleName)
}
fun bar(clazz: kotlin.reflect.KClass<*>) = println(clazz.simpleName)
fun main() { foo<String>() }クイックチェック
型パラメーターをreifiedにするには、何が必要ですか。
まとめ
型消去は、実行時にジェネリック型の情報を削除します。inline関数のreifiedは、呼び出し箇所で型引数を保持し、Tに対するis、as、::class、リフレクションを可能にします。手動でClassオブジェクトを渡す必要はありません。
AI チューターと学ぶ Kotlin — 無料
ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。
- コース
- 51
- レッスン
- 203
よくある質問
「型消去とreified型パラメータ」レッスンは無料ですか?
はい。「型消去とreified型パラメータ」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Kotlin Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Kotlin Academyコースには全4レッスンが含まれています。
「型消去とreified型パラメータ」で何を学びますか?
inline関数でreifiedを使い、実行時に型情報へアクセスします。 ブラウザで直接実行するハンズオンコードでKotlin Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Kotlin Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのKotlin Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「型消去とreified型パラメータ」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このKotlin Academyレッスンでコードを書いて実行できますか?
はい。すべてのKotlin Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- whereによるジェネリック関数と型制約
- 宣言側変性:inとout
- Star Projectionと*の使いどころ
- 型消去とreified型パラメータ