ジェネリック-PECS原則

PECSは、「プロデューサーは、消費者のスーパーを拡張」を参照します。パラメータ化された型は、プロデューサを表す場合言い換えれば、使用は、<?T延び>、それは消費者、使用表す場合<スーパーTを?>。

私は理解していませんか?

見てください<を?Tは拡張>と<?スーパーT>異なります。

<? extends T>そして、<? super T>Javaのジェネリック「ワイルドカード(ワイルドカード)」と「境界線(境界)」という概念です。

  • <? extends T>:手段「上限ワイルドカード(上界ワイルドカード)」
  • <? super T>:それは、「下限ワイルドカード(下の境界ワイルドカード)」を指し、

タイプ定義の数を想像してみて

// レフ1 

クラス食品{} 

// レフ2 

クラスフルーツ延び食品{} 

クラス肉が延び食品{} 

// レフ3 

クラス Appleが延びフルーツ{} 

クラスバナナが延びフルーツ{} 

クラス豚肉が延び肉{} 

クラス牛肉が延び肉{} 

// レフ4 

クラス RedAppleは延びアップル{} 

クラス GreenAppleが延び }アップル{

コンテナ、プレートクラスを定義します。プレートは、一般的な「もの」を置くことができます。

クラスプレート<T> { 

プライベートTアイテム。

公共プレート(T T){アイテム= T;} 

公共 ボイド集合(T T){アイテム= T;} 

パブリック TのGET(){ 戻り項目;} 

}

今、私はもちろん、論理的にフルーツプレートがリンゴをインストールすることができ、「フルーツプレート」を定義します。

プレート<フルーツ> P = 新しいプレート<アップル>(新しいアップル());

しかし、実際にはJavaコンパイラは、この操作を許可していません。彼は、文句を言うでしょうに変換することができない「Appleのプレートがロードされた」「保持フルーツプレート。」

 実際には、良い説明:

  • アップルは、IS-Aフルーツ
  • アップル皿は-IS NOT-ロードされたフルーツプレートを設置しました

だから、コンテナ間の継承関係は、原料で満たされますが、コンテナの間には継承関係が存在しない場合でも。だから、と<? extends T>し、<? super T>。

ワイルドカード上限  Plate<? extends Fruit> 青色に示す下部領域カバレッジを。

 

下部は、ワイルドカード結合  Plate<? super Fruit> 下図の赤の領域を覆います。

 

 

 

 

 

 

 

その後PECS、別の例を見て:

ここでのスタックインタフェースシンプルなAPIは以下のとおりです。

public class  Stack<E>{
    public Stack();
    public void push(E e):
    public E pop();
    public boolean isEmpty();
    //按顺序将一系列元素全部放入Stack中,你可能想到的实现方式如下:
    public void pushAll(Iterable<E> src){
        for(E e : src)
            push(e)
    }
}

这时,有个Stack<Number>,想要灵活的处理Integer,Long等Number的子类型的集合:

Stack<Number> numberStack = new Stack<Number>();
Iterable<Integer> integers = ....;
numberStack.pushAll(integers);

此时代码编译无法通过,因为对于类型Number和Integer来说,虽然后者是Number的子类,但是对于任意Number集合(如List<Number>)不是Integer集合(如List<Integer>)的超类,因为泛型是不可变的。

幸好java提供了一种叫有限通配符的参数化类型,pushAll参数替换为“E的某个子类型的Iterable接口”:

public void pushAll(Iterable<? extends E> src){
    for (E e: src)
        push(e);
}

这样就可以正确编译了,这里的<? extends E>就是所谓的 producer-extends。这里的Iterable就是生产者,要使用<? extends E>。因为Iterable<? extends E>可以容纳任何E的子类。在执行操作时,可迭代对象的每个元素都可以当作是E来操作。

与之对应的是:假设有一个方法popAll()方法,从Stack集合中弹出每个元素,添加到指定集合中去:

public void popAll(Collection<E> dst){
       if(!isEmpty()){
                dst.add(pop());
        }
}

假设有一个Stack<Number>和Collection<Object>对象:

Stack<Number> numberStack = new Stack<Number>();
Collection<Object> objects = ...;
numberStack.popAll(objects);

同样上面这段代码也无法通过,解决的办法就是使用Collection<? super E>。这里的objects是消费者,因为是添加元素到objects集合中去。使用Collection<? super E>后,无论objects是什么类型的集合,满足一点的是他是E的超类,所以不管这个参数化类型具体是什么类型都能将E装进objects集合中去。

 

btw,我们反过来呢?以下两种均不能通过编译。

public void pushAll(Iterable<? super E> src){
    for (E e: src)
        push(e);
}

因为下界规定了元素的最小粒度的下限,实际上是放松了容器元素的类型控制。既然元素是E的基类,那往里存粒度比E小的都可以。但往外读取元素就费劲了,只有所有类的基类Object对象才能装下。但这样的话,元素的类型信息就全部丢失。Stack自然也无法存E的基类。

public void popAll(Collection<? extends E> dst){
       if(!isEmpty()){
                dst.add(pop());
        }
}

原因是编译器只知道容器内是Fruit或者它的派生类,但具体是什么类型不知道。编译器在?标上一个占位符:CAP#1,来表示捕获一个E或E的子类,具体是什么类不知道,代号CAP#1。然后无论是想往里插入A或者B或者C编译器都不知道能不能和这个CAP#1匹配,所以就都不允许。

 

 

This means that when a parameterized type being passed to a method will produce instances of T (they will be retrieved from it in some way), ? extends T should be used, since any instance of a subclass of T is also a T.

When a parameterized type being passed to a method will consume instances of T (they will be passed to it to do something), ? super T should be used because an instance of T can legally be passed to any method that accepts some supertype of T. A Comparator<Number> could be used on a Collection<Integer>, for example. ? extends T would not work, because a Comparator<Integer> could not operate on a Collection<Number>.

--from stackOverFlow https://stackoverflow.com/questions/2723397/what-is-pecs-producer-extends-consumer-super

 

另附阿里java开发手册第一章第五节第6条

6.【强制】泛型通配符<? extends T>来接收返回的数据,此写法的泛型集合不能使用add方 法,而<? super T>不能使用get方法,作为接口调用赋值时易出错。 说明:扩展说一下PECS(Producer Extends Consumer Super)原则:第一、频繁往外读取内 容的,适合用<? extends T>。第二、经常往里插入的,适合用<? super T>。 

 

参考:https://itimetraveler.github.io/2016/12/27/%E3%80%90Java%E3%80%91%E6%B3%9B%E5%9E%8B%E4%B8%AD%20extends%20%E5%92%8C%20super%20%E7%9A%84%E5%8C%BA%E5%88%AB%EF%BC%9F/

https://blog.csdn.net/rj08zhou/article/details/45063451

 

おすすめ

転載: www.cnblogs.com/steve-jiang/p/12172273.html