web-dev-qa-db-ja.com

Java Generics(Wildcards)

Javaの一般的なワイルドカードについていくつか質問があります。

  1. 違いは何ですか List<? extends T>およびList<? super T>

  2. 境界のあるワイルドカードとは何ですか?また、境界のないワイルドカードとは何ですか?

106
Pablo Fernandez

最初の質問で、<? extends T>および<? super T>は、境界付きワイルドカードの例です。無制限のワイルドカードは<?>、および基本的には<? extends Object>。大まかに言って、ジェネリックはどのタイプでもかまいません。境界のあるワイルドカード(<? extends T>または<? super T>extend特定のタイプ(<? extends T>は上限として知られています)、または特定のタイプの祖先である必要があります(<? super T>は下限として知られています)。

Javaチュートリアルには、記事 Wildcards および More Fun with Wildcards でジェネリックのかなり良い説明があります。

120
Bill the Lizard

クラス階層Aがある場合、BはAのサブクラスであり、CとDは両方とも以下のようにBのサブクラスです

class A {}
class B extends A {}
class C extends B {}
class D extends B {}

それから

List<? extends A> la;
la = new ArrayList<B>();
la = new ArrayList<C>();
la = new ArrayList<D>();

List<? super B> lb;
lb = new ArrayList<A>(); //fine
lb = new ArrayList<C>(); //will not compile

public void someMethod(List<? extends B> lb) {
    B b = lb.get(0); // is fine
    lb.add(new C()); //will not compile as we do not know the type of the list, only that it is bounded above by B
}

public void otherMethod(List<? super B> lb) {
    B b = lb.get(0); // will not compile as we do not know whether the list is of type B, it may be a List<A> and only contain instances of A
    lb.add(new B()); // is fine, as we know that it will be a super type of A 
}

境界付きワイルドカードは? extends Bここで、Bは何らかのタイプです。つまり、タイプは不明ですが、「バインド」を配置できます。この場合、それはBのサブクラスであるクラスによって制限されます。

49
oxbow_lakes

Josh Blochは、この中でsuperextendsをいつ使用すべきかについての良い説明も持っています google ioビデオトーク 彼が言及している場所プロデューサーextendsコンシューマーsuperニーモニック。

プレゼンテーションのスライドから:

_Stack<E>_にバルクメソッドを追加するとします。

void pushAll(Collection<? extends E> src);

– srcはEプロデューサーです

void popAll(Collection<? super E> dst);

– dstはEコンシューマです

39
blank

型パラメーターに渡すことができる型の種類を制限したい場合があります。たとえば、数値を操作するメソッドは、Numberまたはそのサブクラスのインスタンスのみを受け入れたい場合があります。これが境界型パラメーターの目的です。

Collection<? extends MyObject> 

IS- A MyObject(つまり、myObject型のオブジェクト、またはMyObjectのサブクラスのオブジェクト)またはMyObjectクラスのオブジェクトとの関係を持つすべてのオブジェクトを受け入れることができることを意味します。

例えば:

class MyObject {}

class YourObject extends MyObject{}

class OurObject extends MyObject{}

その後、

Collection<? extends MyObject> myObject; 

myObjectまたはMyObjectの子のみを受け入れます(つまり、OurObject型またはYourObject型またはMyObject型のオブジェクトは受け入れますが、MyObjectのスーパークラスのオブジェクトは受け入れません)。

3
Sandeep Kumar

一般に、

構造に? extends Eという形式のタイプの要素が含まれている場合、構造から要素を取得できますが、構造に要素を配置することはできません

List<Integer> ints = new ArrayList<Integer>();
ints.add(1);
ints.add(2);
List<? extends Number> nums = ints;
nums.add(3.14); // compile-time error
assert ints.toString().equals("[1, 2, 3.14]"); 

要素を構造に入れるには、Wildcards with superと呼ばれる別の種類のワイルドカードが必要です。

 List<Object> objs = Arrays.<Object>asList(2, 3.14, "four");
    List<Integer> ints = Arrays.asList(5, 6);
    Collections.copy(objs, ints);
    assert objs.toString().equals("[5, 6, four]");

    public static <T> void copy(List<? super T> dst, List<? extends T> src) {
          for (int i = 0; i < src.size(); i++) {
                dst.set(i, src.get(i));
         }
    }
2
Prateek Joshi

事前要件

public class A { }
public class B extends A { }
public class C extends A { }

List<A> listA = new ArrayList<A>();
List<B> listB = new ArrayList<B>();

問題

listB = listA; //not compiled
listA = listB; //not compiled

listB = listA; listAでは、AのインスタンスまたはAのサブクラス(BおよびC)であるオブジェクトを挿入できます。 listB = listAを作成すると、listAに非Bオブジェクトが含まれる危険があります。その後、getlistBからオブジェクトを削除しようとすると、B以外のオブジェクト(AやCなど)が削除される危険があります。これは、listB変数宣言の規約に違反します。

listA = listB;この割り当てを行うことができれば、挿入listBが指すリストにAおよびCインスタンスを作成できます。 Listであると宣言されているlistA参照を介して行うことができます。したがって、挿入 B以外のオブジェクトを、B(またはBサブクラス)インスタンスを保持するように宣言されたリストに入れることができます。

enter image description here

問題

ご覧のとおり、問題はassignmentsにあります。たとえば、この方法で、相対的なリストの要素を処理するメソッドを作成することはできません。

ソリューション

ジェネリックワイルドカードによる救助

List <? extends A>aka 上限 aka covariance aka producersを使用する必要がありますread .get()リストから

コレクション内のインスタンスがAのインスタンスまたはAのサブクラスであることがわかっている場合、読み取りしても安全コレクションのインスタンスであり、それらをAインスタンスにキャストします。

挿入できません要素をリストに追加します。リストがクラスA、B、またはCに入力されているかどうかわからないためです。

List <? super A>aka 下限 aka contravariance aka consumersを使用する必要がありますinsert .add()リストへ

リストがAまたはAのスーパークラスに入力されていることがわかっている場合、挿入しても安全 AのインスタンスまたはAのサブクラス(例:BまたはC)がリストに入力されます。

ただし、読み取りオブジェクトをObjectにキャストする場合を除き、リストから読み取り不可になります。リストに既に存在する要素は、AまたはAのスーパークラスのいずれかのタイプである可能性がありますが、どのクラスであるかを正確に知ることはできません。

enter image description here

詳細をお読みください こちら

1
yoAlex5

汎用ワイルドカードは、コレクションで動作するメソッドをより再利用可能にするために作成されます。

たとえば、メソッドにパラメータList<A>がある場合、このメソッドにはList<A>のみを指定できます。状況によっては、この方法の機能にとっては無駄です。

  1. このメソッドがList<A>からのみオブジェクトを読み取る場合、このメソッドにList<A-sub>を与えることを許可する必要があります。 (A-sub IS a A)
  2. このメソッドがオブジェクトをList<A>にのみ挿入する場合、List<A-super>をこのメソッドに許可する必要があります。 (A IS a-super)
0
taoxiaopang