java ¿Qué es PECS (Producer Extends Consumer Super)?




5 Answers

Los principios detrás de esto en Ciencias de la Computación llevan el nombre de

  • Covarianza -? extiende MyClass,
  • Contravarianza -? super MyClass y
  • Invarianza / No-Varianza - MyClass

La imagen de abajo debe explicar el concepto.

Imagen cortesía de Andrey Tyukin.

java generics super bounded-wildcard pecs

Me encontré con PECS (abreviatura de Producer extends y Consumer super ) mientras leía sobre genéricos.

¿Puede alguien explicarme cómo usar PECS para resolver la confusión entre extends y super ?




public class Test {

    public class A {}

    public class B extends A {}

    public class C extends B {}

    public void testCoVariance(List<? extends B> myBlist) {
        B b = new B();
        C c = new C();
        myBlist.add(b); // does not compile
        myBlist.add(c); // does not compile
        A a = myBlist.get(0); 
    }

    public void testContraVariance(List<? super B> myBlist) {
        B b = new B();
        C c = new C();
        myBlist.add(b);
        myBlist.add(c);
        A a = myBlist.get(0); // does not compile
    }
}



Como explico en mi respuesta a otra pregunta, PECS es un dispositivo mnemotécnico creado por Josh Bloch para ayudar a recordar las tendencias de productos e xtends , más allá s uper .

Esto significa que cuando un tipo parametrizado que se pasa a un método producirá instancias de T (se recuperarán de él de alguna manera) ? extends T Se debe usar la ? extends T , ya que cualquier instancia de una subclase de T es también una T

Cuando un tipo parametrizado que se pasa a un método consumirá instancias de T (se le pasará para que haga algo) ? super T ? super T debería usar ? super T porque una instancia de T se puede pasar legalmente a cualquier método que acepte algún supertipo de T Un Comparator<Number> podría usarse en una Collection<Integer> , por ejemplo. ? extends T ? extends T no funcionaría, porque un Comparator<Integer> no podría operar en una Collection<Number> .

Tenga en cuenta que generalmente solo debe usar ? extends T ? extends T y ? super T ? super T para los parámetros de algún método. Los métodos deberían usar T como el parámetro de tipo en un tipo de retorno genérico.




(Añadiendo una respuesta porque nunca hay suficientes ejemplos con comodines Genéricos)

       // Source 
       List<Integer> intList = Arrays.asList(1,2,3);
       List<Double> doubleList = Arrays.asList(2.78,3.14);
       List<Number> numList = Arrays.asList(1,2,2.78,3.14,5);

       // Destination
       List<Integer> intList2 = new ArrayList<>();
       List<Double> doublesList2 = new ArrayList<>();
       List<Number> numList2 = new ArrayList<>();

        // Works
        copyElements1(intList,intList2);         // from int to int
        copyElements1(doubleList,doublesList2);  // from double to double


     static <T> void copyElements1(Collection<T> src, Collection<T> dest) {
        for(T n : src){
            dest.add(n);
         }
      }


     // Let's try to copy intList to its supertype
     copyElements1(intList,numList2); // error, method signature just says "T"
                                      // and here the compiler is given 
                                      // two types: Integer and Number, 
                                      // so which one shall it be?

     // PECS to the rescue!
     copyElements2(intList,numList2);  // possible



    // copy Integer (? extends T) to its supertype (Number is super of Integer)
    private static <T> void copyElements2(Collection<? extends T> src, 
                                          Collection<? super T> dest) {
        for(T n : src){
            dest.add(n);
        }
    }



Recuerda esto:

El consumidor come la cena (super); Productor amplía la fábrica de sus padres.






Related