sirve simple significa resueltos que poo para metodo llamar herencia ejercicios como comando clase java generics language-design super

java - simple - Genéricos limitantes con la palabra clave ''super''



que significa super() java (4)

¿Por qué puedo usar super solo con comodines y no con parámetros de tipo?

Por ejemplo, en la interfaz de Collection , ¿por qué el método toArray no está escrito así?

interface Collection<T>{ <S super T> S[] toArray(S[] a); }


Como nadie ha proporcionado una respuesta satisfactoria, la respuesta correcta parece ser "Debido a la deficiencia del lenguaje Java".

polygenelubricants proporcionó una buena visión general de las cosas malas que suceden con la covarianza de matriz de Java, que es una característica terrible en sí misma. Considere el siguiente fragmento de código:

String[] strings = new String[1]; Object[] objects = strings; objects[0] = 0;

Este código obviamente incorrecto se compila sin recurrir a ninguna construcción "super", por lo que la covarianza de matriz no se debe utilizar como argumento.

Ahora, aquí tengo un ejemplo perfectamente válido de código que requiere super en el parámetro de tipo nombrado:

class Nullable<A> { private A value; // Does not compile!! public <B super A> B withDefault(B defaultValue) { return value == null ? defaultValue : value; } }

Potencialmente apoyando algún buen uso:

Nullable<Integer> intOrNull = ...; Integer i = intOrNull.withDefault(8); Number n = intOrNull.withDefault(3.5); Object o = intOrNull.withDefault("What''s so bad about a String here?");

El último fragmento de código no se compila si elimino el B completo, por lo que B es realmente necesario.

Tenga en cuenta que la característica que intento implementar se obtiene fácilmente si invierto el orden de las declaraciones de parámetros de tipo, cambiando así la super restricción a extends . Sin embargo, esto solo es posible si reescribo el método como uno estático:

// This one actually works and I use it. public static <B, A extends B> B withDefault(Nullable<A> nullable, B defaultValue) { ... }

El punto es que esta restricción de lenguaje Java está restringiendo algunas características útiles que de otro modo serían posibles y puede requerir soluciones temporales feas. Me pregunto qué pasaría si necesitáramos por withDefault ser virtuales.

Ahora, para correlacionar con lo que dijeron los polilenefrúidos, utilizamos B aquí no para restringir el tipo de objeto pasado como valor defaultValue (vea la Cadena utilizada en el ejemplo), sino para restringir las expectativas de quien llama sobre el objeto que devolvemos. Como regla simple, usa extends con los tipos que demanda y super con los tipos que proporciona.


La respuesta "oficial" a su pregunta se puede encontrar en un informe de error de Sun / Oracle .

BT2: EVALUACIÓN

Ver

http://lampwww.epfl.ch/~odersky/ftp/local-ti.ps

en particular, la sección 3 y el último párrafo de la página 9. La admisión de variables de tipo en ambos lados de las restricciones de subtipo puede dar como resultado un conjunto de ecuaciones de tipo sin la mejor solución; en consecuencia, la inferencia de tipo no se puede hacer utilizando ninguno de los algoritmos estándar existentes. Es por eso que las variables de tipo solo tienen límites "extendidos".

Los comodines, por otro lado, no tienen que inferirse, por lo que no hay necesidad de esta restricción.

@ ###. ### 2004-05-25

Sí; el punto clave es que los comodines, incluso cuando se capturan, solo se utilizan como entradas del proceso de inferencia; nada con (solo) un límite inferior necesita inferirse como resultado.

@ ###. ### 2004-05-26

Veo el problema Pero no veo cómo es diferente de los problemas que tenemos con límites más bajos en los comodines durante la inferencia, por ejemplo:

Lista <? super Número> s;
booleano b;
...
s = b? s: s;

Actualmente, deducimos List <X> donde X extiende Object como el tipo de expresión condicional, lo que significa que la asignación es ilegal.

@ ###. ### 2004-05-26

Lamentablemente, la conversación termina allí. El documento al que solía apuntar el enlace (ahora muerto) es la instanciación de tipo inferido para GJ . Al echar un vistazo a la última página, se reduce a: si se admiten límites inferiores, la inferencia de tipo puede arrojar múltiples soluciones, ninguna de las cuales es principal .


Supongamos que tenemos:

  • clases básicas A> B> C y D

    class A{ void methodA(){} }; class B extends A{ void methodB(){} } class C extends B{ void methodC(){} } class D { void methodD(){} }

  • clases de envoltura de trabajo

    interface Job<T> { void exec(T t); } class JobOnA implements Job<A>{ @Override public void exec(A a) { a.methodA(); } } class JobOnB implements Job<B>{ @Override public void exec(B b) { b.methodB(); } } class JobOnC implements Job<C>{ @Override public void exec(C c) { c.methodC(); } } class JobOnD implements Job<D>{ @Override public void exec(D d) { d.methodD(); } }

  • y una clase de administrador con 4 enfoques diferentes para ejecutar el trabajo en el objeto

    class Manager<T>{ final T t; Manager(T t){ this.t=t; } public void execute1(Job<T> job){ job.exec(t); } public <U> void execute2(Job<U> job){ U u= (U) t; //not safe job.exec(u); } public <U extends T> void execute3(Job<U> job){ U u= (U) t; //not safe job.exec(u); } //desired feature, not compiled for now public <U super T> void execute4(Job<U> job){ U u= (U) t; //safe job.exec(u); } }

  • con el uso

    void usage(){ B b = new B(); Manager<B> managerB = new Manager<>(b); //TOO STRICT managerB.execute1(new JobOnA()); managerB.execute1(new JobOnB()); //compiled managerB.execute1(new JobOnC()); managerB.execute1(new JobOnD()); //TOO MUCH FREEDOM managerB.execute2(new JobOnA()); //compiled managerB.execute2(new JobOnB()); //compiled managerB.execute2(new JobOnC()); //compiled !! managerB.execute2(new JobOnD()); //compiled !! //NOT ADEQUATE RESTRICTIONS managerB.execute3(new JobOnA()); managerB.execute3(new JobOnB()); //compiled managerB.execute3(new JobOnC()); //compiled !! managerB.execute3(new JobOnD()); //SHOULD BE managerB.execute4(new JobOnA()); //compiled managerB.execute4(new JobOnB()); //compiled managerB.execute4(new JobOnC()); managerB.execute4(new JobOnD()); }

¿Alguna sugerencia sobre cómo implementar execute4 ahora?

========== editado =======

public void execute4(Job<? super T> job){ job.exec( t); }

Gracias a todos :)

========== editado ==========

private <U> void execute2(Job<U> job){ U u= (U) t; //now it''s safe job.exec(u); } public void execute4(Job<? super T> job){ execute2(job); }

mucho mejor, cualquier código con U dentro de execute2

súper tipo U se llama!

discusión interesante :)


super para enlazar un parámetro de tipo nombrado (ej. <S super T> ) en oposición a un comodín (ej. <? super T> ) es ILEGAL simplemente porque incluso si está permitido, no haría lo que esperabas que hiciera , porque dado que Object es el super de todos los tipos de referencia, y todo es un Object , en efecto no hay límite .

En su ejemplo específico, dado que cualquier matriz de tipo de referencia es un Object[] (por la covarianza de matriz de Java), puede usarse como argumento para <S super T> S[] toArray(S[] a) (si tal bound es legal) en tiempo de compilación, y no evitará ArrayStoreException en tiempo de ejecución.

Lo que intentas proponer es el dado:

List<Integer> integerList;

y dado este hipotético super límite en toArray :

<S super T> S[] toArray(S[] a) // hypothetical! currently illegal in Java

el compilador solo debe permitir que se compile lo siguiente:

integerList.toArray(new Integer[0]) // works fine! integerList.toArray(new Number[0]) // works fine! integerList.toArray(new Object[0]) // works fine!

y ningún otro tipo de argumentos de matriz (ya que Integer solo tiene esos 3 tipos como super ). Es decir, intenta evitar que esto se compile:

integerList.toArray(new String[0]) // trying to prevent this from compiling

porque, según su argumento, String no es un super de Integer . Sin embargo , Object es un super de Integer , y un String[] es un Object[] , por lo que el compilador aún permitiría la compilación anterior, incluso si hipotéticamente puede hacer <S super T> !

Por lo tanto, lo siguiente aún se compilaría (al igual que en este momento), y ArrayStoreException en tiempo de ejecución no podría evitarse con ninguna comprobación en tiempo de compilación utilizando límites de tipo genérico:

integerList.toArray(new String[0]) // compiles fine! // throws ArrayStoreException at run-time

Los genéricos y las matrices no se mezclan, y este es uno de los muchos lugares donde se muestra.

Un ejemplo no de matriz

De nuevo, digamos que tiene esta declaración de método genérico:

<T super Integer> void add(T number) // hypothetical! currently illegal in Java

Y tienes estas declaraciones variables:

Integer anInteger Number aNumber Object anObject String aString

Su intención con <T super Integer> (si es legal) es que debería permitir add(anInteger) y add(aNumber) , y por supuesto add(anObject) , pero NO add(aString) . Bueno, String es un Object , por lo que add(aString) aún compilaría de todos modos.

Ver también

Preguntas relacionadas

En reglas genéricas de tipeo:

Sobre el uso de super y extends :