はじめに
Kotlin の強力な機能を組み合わせると、
「型安全で、かつジェネリックなユーティリティ関数」を
簡潔に書くことができます。
その中心となるのが:
- 拡張関数(Extension Function)
- inline 関数
- reified 型パラメータ
この3つを組み合わせることで、
Javaでは実現が難しい “型安全な動的処理” が可能になります。
まずは基礎を整理
inline 関数とは?
関数を「インライン展開」する機能。
呼び出し時に関数本体が直接展開され、関数呼び出しのオーバーヘッドが減ります。
inline fun measure(block: () -> Unit) {
val start = System.currentTimeMillis()
block()
println("${System.currentTimeMillis() - start}ms")
}
reified 型パラメータとは?
通常のジェネリクスは「型消去(type erasure)」により、
実行時に型情報が失われます。
fun <T> printType(value: T) {
println(value is String) // ✅ OK
println(T::class) // ❌ Error: reified が必要
}
→ 型パラメータ T は 実行時には存在しない ため、T::class は使えません。
そこで登場するのが reified 修飾子。
inline と組み合わせることで、
実行時にも型情報を利用できるようになります。
基本構文
inline fun <reified T> printType(value: Any) {
if (value is T) {
println("value は ${T::class.simpleName} 型です")
}
}
printType<String>("Hello") // → value は String 型です
printType<Int>(42) // → value は Int 型です
inline + reified の組み合わせにより、
T::class や is T が 実行時にも有効 になります。
実践例①: Intent 拡張関数で型安全な遷移
Android 開発で頻出する Intent の生成。
通常は Class を明示して書きますが、reified で型安全にできます。
inline fun <reified T : Activity> Context.intentFor(): Intent {
return Intent(this, T::class.java)
}
// ✅ 使用例
val intent = context.intentFor<DetailActivity>()
startActivity(intent)
これで:
-
Intent(this, DetailActivity::class.java)を短縮 -
ClassNotFoundExceptionのようなミスを防止 - 型推論で安全に扱える
さらに便利に:引数も安全に渡す
inline fun <reified T : Activity> Context.startActivityWith(vararg extras: Pair<String, Any?>) {
val intent = Intent(this, T::class.java)
extras.forEach { (key, value) ->
when (value) {
is Int -> intent.putExtra(key, value)
is String -> intent.putExtra(key, value)
is Boolean -> intent.putExtra(key, value)
// 必要に応じて型を追加
}
}
startActivity(intent)
}
// ✅ 使用例
startActivityWith<DetailActivity>(
"userId" to 123,
"name" to "Anna"
)
→ 型を安全に分岐させることで、
Intent 引数もスマートに管理できます。
実践例②: JSON 文字列 → 型安全なデシリアライズ
よくある「JSON → Model変換」にも reified は超便利です。
例として Gson を使います:
inline fun <reified T> String.fromJson(): T =
Gson().fromJson(this, T::class.java)
// ✅ 使用例
data class User(val id: Int, val name: String)
val json = """{"id":1,"name":"Anna"}"""
val user = json.fromJson<User>()
println(user.name) // → Anna
→ 通常なら fromJson(json, User::class.java) と書くところを
型推論だけで安全に変換 できるようになります。
実践例③: 汎用 ViewModel 取得関数
Jetpack Compose や Hilt を使う場合にも reified は大活躍。
inline fun <reified VM : ViewModel> Fragment.viewModel(): VM {
return ViewModelProvider(this)[VM::class.java]
}
// ✅ 使用例
val vm = viewModel<MainViewModel>()
→ 型を明示するだけで安全に取得可能。
リフレクション文字列指定のミスを完全防止。
注意点:inline と reified はセットで使う
-
reifiedは inline 関数の中でのみ使用可能 - 通常の関数では型情報が消えるため利用できません
// ❌ コンパイルエラー
fun <reified T> test() { }
// → "Only type parameters of inline functions can be reified"
応用:型安全 Factory 関数
inline fun <reified T> createInstance(): T =
T::class.java.getDeclaredConstructor().newInstance()
val user: User = createInstance() // 型推論で自動生成
→ T::class.java を使えるのは reified のおかげ。
リフレクションを安全に扱える。
まとめ
| キーワード | 説明 |
|---|---|
| inline | 関数呼び出しを展開し、パフォーマンス向上& reified と併用必須 |
| reified | 実行時に型情報を保持できる |
| 拡張関数 | 既存クラスに自然に機能を追加できる |
| 組み合わせ効果 | 型安全 × 冗長性削減 × 可読性向上 |
よくある組み合わせパターン
| 用途 | 関数例 | 備考 |
|---|---|---|
| Activity起動 | Context.intentFor<T>() |
型安全なIntent生成 |
| JSON変換 | String.fromJson<T>() |
汎用デシリアライザ |
| ViewModel取得 | Fragment.viewModel<T>() |
ViewModelProvider連携 |
| Factory生成 | createInstance<T>() |
型からインスタンス生成 |
終わりに
inline + reified + 拡張関数 の組み合わせは、
Kotlin の「表現力」と「安全性」を最大限に引き出すパターンです。
- Javaの反射を置き換えるほど強力
- Intent、JSON、DI、Factory… あらゆる場面で使える
- Kotlinらしい「型安全 × シンプル」な設計
このパターンをマスターすれば、
Kotlinアプリ設計が一段階レベルアップします。
参考
- Kotlin Official Docs: Reified type parameters
- Android Developers: Kotlin Extensions (KTX)