1. ホーム
  2. java

[解決済み] なぜ配列は共変であり、ジェネリックは不変なのですか?

2022-04-15 03:50:14

質問

Effective Java(ジョシュア・ブロック著)より。

  1. 配列は一般的な型と2つの重要な点で異なっています。まず、配列は共変量です。ジェネリックは不変である。
  2. 共変とは、XがYのサブタイプであれば、X[]もY[]のサブタイプになることを意味します。文字列がオブジェクトのサブタイプであるため、配列は共変性です。

    String[] is subtype of Object[]

    不変とは、XがYのサブタイプであるかどうかに関係なく、単純に意味します。

     List<X> will not be subType of List<Y>.
    
    

私の疑問は、なぜJavaで配列を共変量にすることにしたのか、ということです。他にも以下のようなSOの投稿があります。 なぜ配列は不変で、リストは共変なのか? しかし、それらはScalaに焦点を合わせているようで、私はついていけません。

解決方法は?

経由 ウィキペディア :

JavaやC#の初期バージョンにはジェネリックス(別名パラメトリックポリモーフィズム)は含まれていませんでした。

このような環境では、配列を不変にすることで、有用なポリモーフィックプログラムが除外されます。 例えば、配列をシャッフルする関数や、2つの配列が等しいかどうかを Object.equals メソッドを要素に適用します。この実装は、配列に格納されている要素の正確な型に依存しないので、すべての型の配列に対して動作する単一の関数を書くことが可能であるはずです。型の関数を実装するのは簡単です。

boolean equalArrays (Object[] a1, Object[] a2);
void shuffleArray(Object[] a);

しかし,もし配列の型が不変であれば,これらの関数を呼び出すことができるのは Object[] . 例えば、文字列の配列をシャッフルすることはできません。

そのため、JavaもC#も配列の型を共変的に扱います。例えば、C#では string[] のサブタイプです。 object[] であり、Javaでは String[] のサブタイプです。 Object[] .

これは、「なぜ配列は共変するのか」という問いに答えるもので、より正確には「なぜ でした。 配列が共変になる その時 ?quotです。

ジェネリックが導入されたとき、意図的に共変数にしなかったのは、以下の理由で指摘されています。 Jon Skeet氏による回答です。 :

いや、ア 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?

突然ですが、あなたは 非常に と戸惑う猫。

wikipedia の記事にある、配列を共変させるという当初の動機は、ジェネリックスには適用されなかったからです。 ワイルドカード は、共分散(および共分散)の表現を可能にするなど、さまざまな工夫がなされています。

boolean equalLists(List<?> l1, List<?> l2);
void shuffleList(List<?> l);