PECS - [ OHP & Java CANRHEN 11 ]


我々は、参照と議論の容易さのために以下のコードを使用します.
// assignment
List<? extends Number> list1 = new ArrayList<Double>();
List<? super Integer> list2 = new ArrayList<Integer>();

// taking, suppose not empty
Number num1 = list1.get(0); // why works fine?
Integer num2 = list2.get(0); // why compiler-error?

// putting
list1.add(45); // why compiler-error?
list2.add(45); // why works fine?

代入


代入文は、ジェネリックの不変関係を尊重する
// ERROR
List<Number> list1 = new ArrayList<Double>();
// SAFE
List<Integer> list2 = new ArrayList<Integer>();
しかし、制限されたワイルドカードは2つの他の種類の関係を提供します.

共分散
  • 上位のワイルドカードパラメータ化型<? extends Number> )
  • // SAFE
    List<? extends Number> list1 = new ArrayList<Double>();
    

    反対
  • 下位のワイルドカードパラメタ化されたタイプ<? super Integer> )
  • // SAFE
    List<? super Integer> list1 = new ArrayList<Number>();
    
    上記がまだ直観的でないならば、ジェネリックについて前の記事からより多くを発見してください.

    要素へのアクセス


    それで、我々は右側から左側に何を割り当てることができるかについてわかっています.
    変数からアクセスできるものを知ることが重要ですlist1 上記のワイルドカードに保持されている情報に依存します.
    ケース1を見てみましょう.? extends
    List<? extends Number> list1 = new ArrayList<Double>();
    
  • テイク
  • list1 未知の種類の上界Number . 上の制限ワイルドカードの事実に続いて

    A returned object of "unknown" type is known to be compatible with the upper bound.


    上界型のオブジェクトを取得できることを知っています.Number この場合、リストから.
    // SAFE
    List<? extends Number> list1 = new ArrayList<Double>();
    Number num = list1.get(0) // suppose list1 is not empty
    
    何かから物事を取るとき、我々はそれをプロデューサーと呼びます.このように、我々はPECS =の前半を持っています.
  • プット
  • しかし、内部にある未知のタイプとは何かlist1 でしょうInteger , 可能性Double ), 我々は、何かを置くことができませんnull .
    List<? extends Number> list1 = new ArrayList<Double>();
    // ERROR
    list1.add(1); 
    // OK, but not useful
    list1.add(null) 
    
    ケース2を見ましょう? super
    List<? super Integer> list2 = new ArrayList<Integer>();
    
  • テイク
  • list2 未知のタイプの下限Integer . この情報は、Integer 内部ですlist2 . したがって、取り出すことができる唯一の可能なタイプのオブジェクトはそうです.Object .
    List<? super Integer> list2 = new ArrayList<Integer>();
    // ERROR
    Number num = list2.get(0); // suppose not empty
    Integer num = list2.get(0); // suppose not empty
    // OK but not useful
    Object num = list2.get(0);
    
  • プット
  • 下限は、私たちが置くことができる情報を提供しますInteger リストに.これはInteger が下限である.
    したがって、
  • 置換? with Integer ,
  • あなたが得るList<Integer super *whatever super of Integer*>
  • これは常に有効です.
  • <? super Integer> のみを割り当てることができますList<Integer> or List<Number> または任意のスーパータイプInteger 代入
    しかし、コンテナにコンテナを入れて/消費するために、私たちは下界のどんなサブタイプも使うことができます.
  • list2.add(45); すばらしいです
  • list2.add(new A()); も結構ですA extends Integer
  • ここはPECS =>消費者スーパーの後半です.
    私たちはNumber into list2 コンパイラは、List<? super Integer> 参照List<Number> または、おそらくList<Comparable<Integer>> , その場合
  • Number 入るべきではないArrayList<Comparable<Integer>>
  • 同様にComparable<Integer> 入るべきではないArrayList<Number>
  • 詳しく説明する
  • Number 要件に合うクラスです.List<Number super Integer>
  • Comparable<Integer> は要求に合ったインターフェースです.List<Comparable<Integer> super Integer> .
    これは、以下のような代入コールのための作業です.
  • List<? super Integer> l1 = new ArrayList<Number>();
    List<? super Integer> l2 = new ArrayList<Comparable<Integer>>();
    
    したがって、上の2つの可能なケースでは、両方のリストに加えられることができて、まだ意味がある一般的なタイプは何ですか?
    答えはIntegerInteger ).

    結論


    私がいつかそれを必要とするとき、私がそれを参照することができるように、私はこれを書きます😏


    参考文献


    ジェネリックFAQ here and FAQ here