Kotlinにおける型チェックは、単なる「instanceofの代替」ではありません。
Kotlinは、安全性・可読性・保守性を高めるために、型チェックと型推論を密接に連携させる設計を採用しています。
本記事では、Kotlinの型チェックについて、
- 基本構文
- スマートキャストが成立する条件
- 安全キャストと例外の扱い
- null・ジェネリクスとの関係
- 実務で安全な書き方
という観点から、誤解が生じないよう正確に解説します。
Kotlinにおける型チェックとは
型チェックとは、
ある値が、指定した型のインスタンスであるかを判定すること
です。
Kotlinではこの判定結果をもとに、コンパイラが安全だと判断できる場合に限り、自動的に型を絞り込む(スマートキャスト)という点が最大の特徴です。
is 演算子による型チェック(基本)
Kotlinでは is 演算子を使って型を判定します。
val obj: Any = "Hello"
if (obj is String) {
println(obj.length)
}
特徴
- Javaの
instanceofに相当 - 実行時に型を判定する
- 条件式が真の場合、後続処理でスマートキャストが発生する
スマートキャストとは何か
スマートキャストの概要
スマートキャストとは、
型チェック後、明示的なキャストを書かなくても、その型として扱える仕組み
です。
fun printLength(obj: Any) {
if (obj is String) {
// obj は String として扱われる
println(obj.length)
}
}
Javaではキャストが必須ですが、Kotlinでは不要です。
スマートキャストが成立する条件
スマートキャストは 常に使えるわけではありません。
成立条件は次の一点に集約されます。
コンパイラが「この値は、この後も同じ型のままである」と保証できること
スマートキャストが成立しやすい例
if (obj is String) {
println(obj.length)
}
- ローカル変数
- チェック後に再代入されていない
- カスタム getter を持たない
スマートキャストが成立しない典型例
class Sample {
var value: Any = "Hello"
}
if (sample.value is String) {
println(sample.value.length) // コンパイルエラー
}
理由
valueがvar- getter を通じて取得される
- コンパイラが「同じ値が返り続ける」と証明できない
ここで重要なのは、スレッドの有無ではなく「変更可能性を否定できないこと」です。
!is 演算子とガード節
型チェックの否定には !is を使います。
if (obj !is String) return
println(obj.length)
この書き方は ガード節 と呼ばれ、以降の処理で型が確定していることを明示できるため、実務で非常によく使われます。
明示的キャスト:as と as?
危険なキャスト:as
val obj: Any = "Hello"
val str: String = obj as String
- キャスト不能 → ClassCastException
- Javaのキャストと同等
- 制御フローに使うべきではない
安全なキャスト:as?
val obj: Any = 123
val str: String? = obj as? String
挙動は次の通りです。
- キャスト成功 → 対象型の値
- キャスト失敗 →
null - 左辺が
null→null
val length = (obj as? String)?.length
例外を発生させずに処理できるため、実務では as? が推奨されます。
when 式と型チェック
when と型チェックの組み合わせは、Kotlinらしい代表的な書き方です。
fun handle(obj: Any) {
when (obj) {
is String -> println(obj.length)
is Int -> println(obj + 1)
is List<*> -> println(obj.size)
else -> println("Unknown")
}
}
ポイント
- 各分岐でスマートキャストが有効
- 可読性が高い
- 型ごとの処理が明確
null と型チェックの関係
nullチェックとスマートキャスト
val text: String? = "Hello"
if (text != null) {
println(text.length)
}
null チェック後もスマートキャストが働きます。
is と null
val text: String? = null
println(text is String) // false
println(text is String?) // true
null is String→ falsenull is String?→ true(nullable型に含まれるため)
ジェネリクスと型チェック
JVMでは 型消去 が行われるため、次のようなチェックはできません。
if (obj is List<String>) { // コンパイルエラー
}
回避策①:スター投影
if (obj is List<*>) {
println(obj.size)
}
回避策②:reified 型パラメータ
inline fun <reified T> isType(value: Any): Boolean {
return value is T
}
型チェックとパフォーマンスについて
isやwhenは通常問題にならない- 例外(
asの失敗)を制御フローに使うのは避ける - 安全キャスト+null処理が最も安定
パフォーマンスよりも 安全性・可読性を優先するのがKotlinの設計思想です。
実務で安全な定型パターン
val str = obj as? String ?: return
println(str.length)
when (obj) {
is String -> ...
is Int -> ...
else -> ...
}
if (obj is String && obj.isNotEmpty()) {
...
}
まとめ
Kotlinの型チェックは、
isによる安全な判定- コンパイラによるスマートキャスト
as?による例外回避- null・ジェネリクスとの一貫した設計
によって、「安全に書けて、読みやすく、壊れにくいコード」を実現します。
単に書き方を覚えるのではなく、
「なぜスマートキャストが効くのか/効かないのか」
を理解すると、Kotlinコードの品質が一段上がります。
以上、Kotlinの型チェックについてでした。
最後までお読みいただき、ありがとうございました。










