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



Answers

Los principios detrás de esto en Ciencias de la computación lleva el nombre de

  • Covarianza -? extiende MyClass,
  • Contravarianza -? super MyClass y
  • Invarianza / no varianza - MyClass

La siguiente imagen debe explicar el concepto.

Cortesía de la imagen: Andrey Tyukin

Question

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

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




Como explico en mi respuesta a otra pregunta, PECS es un dispositivo mnemónico creado por Josh Bloch para ayudar a recordar P roducer e xtends , C onsumer s uper .

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

Cuando un tipo parametrizado que se pasa a un método consumirá instancias de T (se pasarán a él para hacer algo) ? super T debe usarse ? super T porque una instancia de T puede pasarse 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 debería estar utilizando ? extends T ? extends T y ? super T ? super T para los parámetros de algún método. Los métodos deberían simplemente usar T como parámetro de tipo en un tipo de devolución genérico.




(agregando una respuesta porque nunca hay suficientes ejemplos con los comodines de Generics)

       // 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);
        }
    }



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
    }
}



Related