配列よりリストを選ぶ
配列とジェネリック型の違いとして、
- 配列は共変であり、ジェネリック型は不変である
- 配列は具象化(実行時にその要素型を知っていて、強制すること)だが、ジェネリックスはイレイジャ(コンパイル時にのみ型制約を強制し、実行時に型情報を廃棄すること)
E、List<E>
、そして、List<String>
は、技術的には具象化不可能型(nonreifiable type)として知られています。
直感的に言えば、具象化不可能型は、その実行時の表現がコンパイル時の表現よりも情報が少ない型です。
具象化可能な唯一のパラメータ化された型は、List<?>
やMap<?, ?>
などの非境界ワイルドカード型です。非境界ワイルドカード型の配列の生成は許されていますが、稀にしか有用ではありません。
ジェネリック配列生成の禁止は、煩わしいかもしれません。例えば、一般にジェネリック型は、その要素型の配列を返すことが不可能です。
可変長引数のメソッドをジェネリック型と組み合わせて使用する場合、困惑する警告が出る可能性も意味しています。それは、可変長引数のメソッドを呼び出すと、必ず可変長パラメータを保持するために配列が生成されるからです。
(下記のコードでいうと、argsがそれに該当する)
static int sum(int... args) {
int sum = 0;
for (int arg : args) {
sum += arg;
}
return sum;
}
この配列の要素型が具象化可能でなければ、警告が出ます。その警告を抑制することとAPIでジェネリックスと可変長引数を混在させないようにすること以外に、警告に対してできることはほとんどありません。
ジェネリック配列生成エラーとなる場合には、最善の解決策は、配列型E[]
よりはコレクション型List<E>
を大抵は使用することです。
何らかのパフォーマンスや簡潔さを犠牲にするかもしれませんが、代わりに、より良い型安全性と相互運用性を得ます。