2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

JavaのList<?extends T>へのget/add、List<?super T>へのget/add

Last updated at Posted at 2016-08-20

具体的な型

class
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といいます。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?