放課後プログラミング

調べたことや考えたことなどを忘れないために書きます。

知らないと混乱するJavaの変性

変性とはすなわち、共変性・反変性・非変性(不変性)のことで、

共変 (covariant): 広い型(例:double)から狭い型(例:float)へ変換すること。
反変 (contravariant) : 狭い型(例:float)から広い型(例:double)へ変換すること。
不変 (invariant): 型を変換できないこと。

wikipedia:共変性と反変性_(計算機科学)

狭いとは機能が狭いという意味で、JavaのクラスではObject型が一番狭く、そのサブクラスはObject型より機能が拡張されているため広い型ということになります。
Javaの変性について調べたので下記に簡単にまとめました。

//プリミティブ型
float flt;
double dbl = 1.0D;
flt = dbl; // NG // コンパイルエラー「Error: java: 不適合な型: 精度が失われる可能性があるdoubleからfloatへの変換」
dbl = flt; // OK //
// Javaのプリミティブ型は反変です。狭い型から広い型へ代入すると、なかった情報は勝手に補完されます。


//プリミティブ配列型
float[] fltArr;
double[] dblArr = new double[1];
fltArr = dblArr; // NG // コンパイルエラー「Error: java: 不適合な型: double[]をfloat[]に変換できません:」
dblArr = fltArr; // NG // コンパイルエラー「Error: java: 不適合な型: float[]をdouble[]に変換できません:」
//プリミティブ配列型は非変です。


//複合データ型
class A {}
class B extends A {}
A a;
B b = new B();
a = b; // OK //
b = a; // NG // コンパイルエラー「Error: java: 不適合な型: AをBに変換できません:」
// プリミティブ型とは逆に、複合データ型は共変です。広い型から狭い型に代入すると、溢れた情報は失われます。


//複合データ配列型
A[] aArr;
B[] bArr = new B[1];
aArr = bArr; // OK //
bArr = aArr; // NG // コンパイルエラー「Error: java: 不適合な型: org.example.A[]をorg.example.B[]に変換できません:」
// 複合データ型と同様に共変です。


//総称型
List<A> listA;
List<B> listB = new ArrayList<>();
listA = listB; // NG //  コンパイルエラー「Error: java: 不適合な型: java.util.List<B>をjava.util.List<A>に変換できません:」
listB = listA; // NG //  コンパイルエラー「Error: java: 不適合な型: java.util.List<A>をjava.util.List<B>に変換できません:」
// 総称型は非変です。共変性や反変性を適用したい場合はワイルドカードを使います。