una superclase sobreescribir metodo herencias hacer ejemplo crear como clases java generics

superclase - super() java



java genéricos super palabra clave (6)

Revisé estos temas

Sin embargo, todavía parezco perdido con la palabra clave super :

  1. Cuando declaramos una colección como esa:

    List<? super Number> list = null; list.add(new Integer(0));//this compiles list.add(new Object());//this doesn''t compile

    ¿No debería ser lo contrario? Tenemos una lista que contiene algunos objetos (de tipo desconocido) que son los padres de Number . Así que Object debería caber (ya que es el padre del Number ), y Integer no debería. Lo contrario es el caso por alguna razón.

  2. Siempre que tengamos el siguiente código

    static void test(List<? super Number> param) { param.add(new Integer(2)); } public static void main(String[] args) { ArrayList<String> sList = new ArrayList<String>(); test(sList); //will never compile, however... }

    Es imposible compilar el código anterior (y mi cordura sugiere que este es el comportamiento correcto), pero la lógica básica podría demostrar lo contrario:

    String is Object, Object is superclass of Number. So String should work.

    Sé que esto es una locura, pero ¿no es esta la razón por la que no permitieron construcciones <S super T> ? Si es así, ¿por qué <? super T> <? super T> está permitido?

¿Alguien podría ayudarme a restaurar la parte que falta de esta cadena lógica?


El comodín delimitado en List<? super Number> List<? super Number> puede capturar Number y cualquiera de sus supertipos. Dado que Number extends Object implements Serializable , esto significa que los únicos tipos que actualmente se pueden capturar son convertibles mediante List<? super Number> List<? super Number> son:

  • List<Number>
  • List<Object>
  • List<Serializable>

Tenga en cuenta que puede add(Integer.valueOf(0)) a cualquiera de los tipos anteriores. sin embargo, NO PUEDE add(new Object()) a una List<Number> o una List<Serializable> , ya que eso infringe la regla de seguridad de tipo genérico.

Por lo tanto, NO es cierto que pueda add un supertipo de Number a una List<? super Number> List<? super Number> ; simplemente no es así cómo funciona la conversión de comodines y captura delimitada. Usted no declara una List<? super Number> List<? super Number> porque es posible que desee agregarle un Object (¡no puede!); lo haces porque deseas agregarle objetos Number (es decir, es un "consumidor" de Number ), y simplemente una List<Number> es demasiado restrictiva.

Referencias

Ver también

  • Effective Java 2nd Edition , Item 28: Use comodines delimitados para aumentar la flexibilidad de la API
    • "PECS significa productor- extends , consumidor- super

Preguntas relacionadas

  • Demasiados para listar, PECS, new Integer(0) vs valueOf , etc.

No lo entendí por un tiempo. Muchas de las respuestas aquí y otras preguntas muestran específicamente cuándo y dónde ciertos usos son errores, pero no tanto por qué.

Así es como finalmente lo conseguí. Si tengo una función que agrega Number s a una List , me gustaría agregarlos de tipo MySuperEfficientNumber que es mi propia clase personalizada que implementa Number (pero no es una subclase de Integer ). Ahora es posible que la persona que llama no sepa nada sobre MySuperEfficientNumber , pero siempre que sepa que trata los elementos agregados a la lista como nada más específico que Number , estarán bien.

Si declaro mi método como:

public static void addNumbersToList(List<? extends Number> numbers)

Entonces la persona que llama podría pasar en una List<Integer> . Si mi método agregara un MySuperEfficientNumber al final de los numbers , la persona que llama ya no tendría una List de Integer y el siguiente código no funcionaría:

List<Integer> numbers = new ArrayList<Integer>(); addNumbersToList(numbers); // The following would return a MySuperEfficientNumber not an Integer Integer i = numbers.get(numbers.size()-1)

Obviamente esto no puede funcionar. Y el error estaría dentro del método addNumbersToList . Obtendrás algo como:

The method add... is not applicable for the arguments (MySuperEfficientNumber)

Porque los numbers pueden ser cualquier tipo específico de Number , no necesariamente algo con lo que MySuperEfficientNumber es compatible. Si volteaba la declaración para usar super , el método se compilaría sin error, pero el código de la persona que llama fallaría con:

The method addNumbersToList(List<? super Number>)... is not applicable for the arguments (List<Integer>)

Debido a que mi método dice: "No crea que su List puede ser más específica que el Number . Podría agregar todo tipo de Number extraños a la lista, solo tendrá que lidiar con eso. pensar en ellos como algo incluso más general que Number - like Object - está bien, te garantizo que serán al menos Number s, pero puedes tratarlos de manera más general si quieres ".

Mientras que extends dice: "Realmente no me importa qué tipo de List me proporciones, siempre que cada elemento sea al menos un Number . Puede ser cualquier tipo de Number , incluso tu propio Number extraño, personalizado y confeccionado s. Mientras implementen esa interfaz, estamos bien. No voy a agregar nada a su lista, ya que no sé qué tipo de hormigón real está utilizando allí ".


Para la primera parte, la List<Number> cabe en la List<? super Number> List<? super Number> pero no puede agregar un Object a una List<Number> . Es por eso que no puede agregar un Object a la List<? super Number> List<? super Number> .

Por otro lado, puede agregar todas las subclases de Number ( Number incluido) a su lista.

Para la segunda parte, String es un Object , pero String no es una superclase de Number .

Si funcionara así, ya que cada clase es una subclase de Object , super no tendría ningún significado.

Veamos todos los casos posibles con List<? super Number> List<? super Number> :

  • La lista pasada es una List<Object>
    • List<Object> funcionará
    • Object ajusta en <? super Number> <? super Number>
    • Puede agregar cualquier subtipo de Number a una List<Object>
    • Incluso si también pudiera agregar String lo único de lo que está seguro es que puede agregar cualquier subclase de Number .
  • La lista aprobada es una List<Number> :
    • List<Number> funcionará
    • Number cabe en <? super Number> <? super Number>
    • Puede agregar cualquier subtipo de Number a una List<Number>
  • La lista pasada es una List<Integer> (o cualquier subclase de Number ):
    • List<Integer> no funcionará
    • Integer es una subclase de Number por lo que es exactamente lo que queremos evitar
    • Incluso si un Integer encaja en un Number , no podría agregar ninguna subclase de Number en una List<Integer> (por ejemplo, un Float )
    • super no significa una subclase.
  • La lista pasada es una List<String> (o cualquier clase que no se extiende Number ni en la "súper jerarquía" de Number (es decir, Number y Object ):
    • List<String> no funcionará
    • String no cabe en el Number "súper jerarquía"
    • Incluso si String encaja en Object (que es una superclase de Number ) no estarás seguro de poder agregar un Number a una List que contenga cualquier subclase de una de las superclases de Number )
    • super no significa ninguna subclase de una de las súper clases, solo significa una de las súper clases.

Como funciona ?

Podría decir que siempre que pueda agregar cualquier subclase de Number con su List tipeada, respetará la palabra clave super .


Yo tuve el mismo problema. Creo que la sintaxis es la causa de la confusión.

List<? super Number> List<? super Number> parece sugerir " una lista de cosas que son supertipos de Número ", pero lo que realmente significa es " una lista de cosas que tienen Número como su supertipo ".

Una vez que comencé a leerlo, hizo clic.


List<? super Number> List<? super Number> es una List<AncestorOfNumber> donde podemos convertir implícitamente cada Number a su tipo super AncestorOfNumber .

Considere esto: ¿Qué tipo genérico necesita ser ???? en el siguiente ejemplo?

InputStream mystream = ...; void addTo(List<????> lsb) { lsb.add(new BufferedInputStream(mystream)); } List<BufferedInputStream> lb = new ArrayList<>(); List<InputStream> li = new ArrayList<>(); List<Object> lo = new ArrayList<>(); ... { addTo(lb); addTo(li); addTo(lo); }

La respuesta: ???? es algo a lo que podemos lanzar BufferedInputStream , que es ese mismo o uno de sus antepasados ? super BufferedInputStream ? super BufferedInputStream


List<? super Number> List<? super Number> significa que el tipo de referencia de la variable sugiere que tenemos una lista de números, objetos o serializables.

La razón por la que no puede agregar un Objeto, es porque el Compilador no sabe CUÁLES de estas clases están en la definición genérica del objeto instanciado real, por lo que solo le permite pasar Número o subtipos de Número, como Doble, Entero y pronto.

Digamos que tenemos un método que devuelve una List<? super Number> List<? super Number> . La creación del objeto dentro del método está encapsulada desde nuestra vista, simplemente no podemos decir si es algo como esto:

List<? super Number> returnValue = new LinkedList<Object>();

o

List<? super Number> returnValue = new ArrayList<Number>();

Entonces, el tipo genérico podría ser Objeto o Número. En ambos casos, podríamos agregar Number, pero solo en un caso podríamos agregar Object.

Debe distinguir entre el tipo de referencia y el tipo de objeto real en esta situación.