ウィキペディア経由:
JavaおよびC#の初期のバージョンにはジェネリック(別名パラメトリックポリモーフィズム)が含まれていませんでした。
このような設定では、配列を不変にすると、有用な多態性プログラムが除外されます。たとえば、配列をシャッフルする関数、またはObject.equals
要素のメソッドを使用して2つの配列が等しいかどうかをテストする関数を書くことを検討してください。実装は、配列に格納されている要素の正確なタイプに依存しないため、すべてのタイプの配列で機能する単一の関数を記述できるはずです。タイプの機能を実装するのは簡単です
boolean equalArrays (Object[] a1, Object[] a2);
void shuffleArray(Object[] a);
ただし、配列型が不変として扱われた場合、これらの関数を呼び出すことができるのは、その型の配列に対してのみObject[]
です。たとえば、文字列の配列をシャッフルすることはできません。
したがって、JavaとC#はどちらも配列型を共変的に扱います。たとえば、C#string[]
ではのサブタイプでobject[]
あり、Java String[]
ではのサブタイプですObject[]
。
これは質問より正確に「なぜ?配列は共変である」、またはに答え、「なぜだったの配列は共変をした時に?」
ジェネリックが導入されたとき、Jon Skeetがこの回答で指摘した理由により、ジェネリックは意図的に共変にされませんでした:
いいえ、a List<Dog>
はではありませんList<Animal>
。あなたが何ができるかを考えてくださいList<Animal>
-あなたはそれにどんな動物も加えることができます...猫を含めて。今、あなたは子犬のトイレに猫を論理的に追加できますか?絶対違う。
// Illegal code - because otherwise life would be Bad
List<Dog> dogs = new List<Dog>();
List<Animal> animals = dogs; // Awooga awooga
animals.add(new Cat());
Dog dog = dogs.get(0); // This should be safe, right?
突然あなたは非常に混乱した猫を飼っています。
ウィキペディアの記事で説明されている配列を共変にする元の動機はジェネリックには当てはまりませんでした。これは、ワイルドカードによって共分散(および反変)の表現が可能になったためです。次に例を示します。
boolean equalLists(List<?> l1, List<?> l2);
void shuffleList(List<?> l);