1. スター投影とは?
スター投影 (\*) とは、
「型パラメータが不明または気にしない場合 に使う」
ジェネリクスの省略記法です。
つまり、「型を特定しないけど、安全に使いたい」時の仕組み。
例:
val list: List<*> = listOf("A", "B", "C")
この List<*> は
「どんな型の要素を持っているか分からない List」を意味します。
2. スター投影を使う理由
Kotlin ではジェネリクスを使うと型安全になりますが、
ときには「型がわからないけどとりあえず扱いたい」ことがあります。
例:
fun printList(list: List<*>) {
for (item in list) {
println(item)
}
}
この関数は、List<String> でも List<Int> でも呼び出せます。
3. 読み取りはできるが、書き込みはできない
val list: MutableList<*> = mutableListOf("A", "B")
// list.add("C") ❌ コンパイルエラー
val item = list[0] // ✅ 読み取り可能(型は Any?)
理由:
- 型パラメータが不明なため、何を追加しても安全とは限らない。
- でも、既にある要素を「読み取る」ことは安全。
4. スター投影の型の意味
Kotlin コンパイラは * を次のように解釈します。
| 宣言 | スター投影に展開される実際の型 | 意味 |
|---|---|---|
T |
out Any? |
読み取り専用(すべての型を許す) |
in T |
in Nothing |
書き込み禁止 |
out T |
out Any? |
読み取り専用 |
つまり:
スター投影された型は「読むことはできるが、書くことはできない」。
5. Map の例(複数型パラメータ)
スター投影は複数の型パラメータにも使えます。
val map: Map<*, *> = mapOf(1 to "One", 2 to "Two")
for ((key, value) in map) {
println("$key → $value")
}
ここでの Map<*, *> は
「キーの型も値の型も分からないが、読み取りは安全」という意味です。
6. 実際の活用例
例1:型パラメータを気にしない共通関数
fun printSize(list: List<*>) {
println("Size: ${list.size}")
}
printSize(listOf("A", "B", "C"))
printSize(listOf(1, 2, 3))
例2:リフレクションやAPIで「型が不明なとき」
fun printElements(list: List<*>) {
list.forEach { println(it) }
}
型を指定できない場合でも、安全にアクセス可能。
7. Java のワイルドカードとの比較
| Java | Kotlin | 意味 |
|---|---|---|
List<?> |
List<*> |
不特定な型のリスト |
List<? extends T> |
List<out T> |
T のサブタイプ(共変) |
List<? super T> |
List<in T> |
T のスーパータイプ(反変) |
Kotlin は in / out で明確に「共変/反変」を指定できるため、
Java よりシンプルです。
8. スター投影と他の概念の関係
| 概念 | 役割 | 説明 |
|---|---|---|
out |
共変 | 「出すだけOK」 |
in |
反変 | 「入れるだけOK」 |
* |
スター投影 | 「型を気にせず安全に読むだけ」 |
スター投影は、共変/反変を明示できないときの「安全なデフォルト扱い」。
まとめ
| 特徴 | 内容 |
|---|---|
| 記法 |
List<*>, Map<*, *>
|
| 意味 | 「型が分からないけど安全に使いたい」 |
| 読み取り | OK(型は Any?) |
| 書き込み | 不可 |
| Java との対応 |
<?> に相当 |
| 内部的展開 |
out Any? または in Nothing に置換される |