具体的な型
class Animal(){
}
class Dog extends Animal(){
}
class Puppy extends Dog(){
}
DogはAnimalのサブクラスとします
PuppyはDogのサブクラスとします
new ArrayList extends Animal>とか
new ArrayList super Dog>などのワイルドカードオブジェクトを生成できません
ワイルドカード型はメソッドのパラメータ型に使います
List<?extends Animal>
要素追加 add 不可能
void func(List<?extends Animal>p)
のメソッド内では
p.add(animal);
p.add(dog);
は共にコンパイルエラーになります。
List<?extends Animal>型であるpは、List<Puppy>である可能性もあります。List<Puppy>型リストには、animalもdogも追加できません。pはPuppyよりさらに子孫のクラスのListの可能性もあります。結局List<?extends Animal>pには、(nullを除き)どのようなオブジェクトもaddできません。
※?extends Animalだから、Animalの子孫クラスならaddできると考えてはいけません。
要素読み出し get 安全
void func(List<?extends Animal>p)
のメソッド内では
Animal a=p.get(0)できます。pはList<Animal>とは限らず、List<Dog>やList<Puppy>の可能性があります。いずれにせよ、List<?extends Animal>型Listオブジェクトからgetした要素をAnimal型に代入することはアップキャストになり、安全に要素を読み取ることができます。func(List<?extends Animal>p)はpからAnimal型要素を取り出すのに使います。
List<?super Dog>
要素追加 add Dogの子孫クラスオブジェクトなら可能
void func(List<?super Dog>p)
のメソッド内では
p.add(New Animal());//<=これはコンパイルエラー
p.add(New Dog());//有効
p.add(New Puppy());//有効
※?suprt Dogだから、Dogの先祖クラスならaddできると考えてはいけません。
pはList<Dog>かもしれませんが、List<Animal>やList<Object>である可能性もあります。これらのListオブジェクトに対して安全にaddできるのは、Dogの子孫クラスのオブジェクトです。func(List<?super Dog>p)はpにDog型(及びその子孫クラスのオブジェクト)要素を追加するために使われます。
要素読み出し get 危険なので禁止
void func(List<?super Dog>p)
のメソッド内でpから要素を取り出すことはできます。
Dog dog=p.get(0);
これはコンパイラエラーにはなりません。しかし、pはListやListであるかもしれません。よって、取り出した要素はObject型である可能性もあり、Dog dog=p.get(0);はダウンキャストになり、その場合はランライムエラーで例外が発生します。結局List<?super Dog>から要素を読み出して何らかのクラスにキャストするのは危険で、読み出し禁止扱いとします。
PECS
キューやネットワークなどを介して、一連のオブジェクトを入力として、別の一連のオブジェクトを出力するソフトウェア構造をProducer/Consumerモデルといいます。Producer/Consumerモデルが入力として受け付けるオブジェクトの型がAnimalの場合、入力となる一連のデータを受け取るメソッドをifunc(List<?extends Animal>p)のようにしておくと、ifuncにはList<Animal>、List<Dog>、List<Puppy>のいずれのリストもifuncに渡せます。
Producer/Consumerモデルが出力するオブジェクトの型が例えばDog型の場合、出力を受け取るメソッドをofunc(List<?suprt Dog>p)のようにしておきます。もし出力されたオブジェクトを単にAnimal型としてしか扱わなければ、ofuncのパラメータにはわざわざList<Dog>ではなくList<Animal>型のListオブジェクトを渡して、出力をそのリストに格納できます。
このようにProducer側の入力パラメータをextendsして、Consumer側のデータを格納するパラメータをsuperする習慣をPECSといいます。