【きょうへんせいとはんへんせい】

共変性と反変性 とは?

💡 「親子関係がコンテナにも伝わるか?」型安全の奥にある継承のルール。
📌 このページのポイント
共変性・反変性・不変性 継承関係 Animal Cat Cat は Animal の子 共変性 Producer<Cat> Producer<Animal> ✓ OK(出力側) Kotlin: out 反変性 Consumer<Animal> Consumer<Cat> ✓ OK(入力側) Kotlin: in 不変性 List<Cat> ✗ NG List<Animal> 互換なし Java default 「読み出し専用なら共変、書き込み専用なら反変、両方なら不変」 Java ワイルドカード: <? extends T>(共変) / <? super T>(反変) TypeScript の配列は共変(読み書き両方可だが便宜上)
共変性・反変性・不変性 ── ジェネリクスへの継承関係の伝わり方
ひよこ ひよこ

`List` って `List` として渡せないの? Cat は Animal なのに!

ペンギン先生 ペンギン先生

それが型安全の落とし穴なんだ。もし `List` を `List` として使えると、「Dogを追加する」操作もできてしまって、Catしか入っていないはずのリストが壊れてしまうよ。

ひよこ ひよこ

じゃあ共変性ってどういうときに使えるの?

ペンギン先生 ペンギン先生

読み取り専用のとき(出力側)は安全に使えるんだ。`Producer` を `Producer` として扱うのはOKだよ。Cat を返すものは Animal を返すものとして使えるからね。Kotlinでは `out` キーワードで指定するよ。

ひよこ ひよこ

反変性っていうのは逆なの?

ペンギン先生 ペンギン先生

そうだよ。書き込み専用のとき(入力側)は反変性が使えるんだ。`Consumer` を `Consumer` として使えるよ。Animal を受け取れるものは当然 Cat も受け取れるから安全なんだ。Kotlinでは `in` キーワードを使うね。

ひよこ ひよこ

不変性っていうのが一番厳しいの?

ペンギン先生 ペンギン先生

そうだね。読み書き両方できる場合は安全のために不変性にするしかないんだ。JavaのGenericsはデフォルトで不変だよ。ただワイルドカード(`? extends Animal` や `? super Cat`)で共変・反変を表現できるようになっているよ。

ペンギン
まとめ:ざっくりこれだけ覚えればOK!
「共変性と反変性」って出てきたら「ジェネリクス継承関係が伝わるかどうかのルール」と思えればだいたいOK!
📖 おまけ:英語の意味
「Covariance and Contravariance」 = 共変性と反変性
💬 co- は「一緒に」contra- は「反対に」という意味の接頭辞で、型パラメータの変化が元の型の継承方向と同じか逆かを表しているんだよ。
← 用語集にもどる