Después de de nuestra prolongada recopilación de datos dimos con la solución esta pregunta que suelen tener muchos de nuestros lectores. Te ofrecemos la respuesta y nuestro objetivo es servirte de mucha ayuda.
Solución:
Tampoco estoy seguro de por qué la restricción está ahí. Podría intentar enviar un correo electrónico amistoso a los diseñadores de Java 5 Generics (principalmente Gilad Bracha y Neal Gafter).
Supongo que querían admitir solo un mínimo absoluto de tipos de intersección (que es lo que esencialmente son los límites múltiples), para que el lenguaje no sea más complejo de lo necesario. Una intersección no se puede utilizar como una anotación de tipo; un programador solo puede expresar una intersección cuando aparece como el límite superior de una variable de tipo.
¿Y por qué se apoyó este caso? La respuesta es que los límites múltiples le permiten controlar el borrado, lo que permite mantener la compatibilidad binaria al generar clases existentes. Como se explica en la sección 17.4 del libro de Naftalin y Wadler, un max
El método lógicamente tendría la siguiente firma:
public static > T max(Collection extends T> coll)
Sin embargo, esto se borra a:
public static Comparable max(Collection coll)
Que no coincide con la firma histórica de max
, y hace que los clientes antiguos se rompan. Con múltiples límites, solo el límite más a la izquierda se considera para el borrado, por lo que si max
se da la siguiente firma:
public static > T max(Collection extends T> coll)
Entonces el borrado de su firma se convierte en:
public static Object max(Collection coll)
Que es igual a la firma de max
antes de los genéricos.
Parece plausible que los diseñadores de Java solo se preocuparon por este caso simple y restringieron otros usos (más avanzados) de los tipos de intersección porque simplemente no estaban seguros de la complejidad que podría traer. Por lo tanto, el motivo de esta decisión de diseño no tiene por qué ser un posible problema de seguridad (como sugiere la pregunta).
Más discusión sobre los tipos de intersección y las restricciones de los genéricos en un próximo documento de OOPSLA.
Dos posibles razones para prohibir esto:
-
Complejidad. JDK-4899305 sugiere que un límite que contenga un parámetro de tipo más tipos parametrizados adicionales permitiría tipos mutuamente recursivos aún más complicados que los que ya existen. En resumen, la respuesta de Bruno.
-
La posibilidad de especificar tipos ilegales. Específicamente, extender una interfaz genérica dos veces con diferentes parámetros. No puedo encontrar un ejemplo no artificial, pero:
/** Contains a Comparator
that also implements the given type T. */ class StringComparatorHolder > private final C comparator; // ... void foo(StringComparatorHolder , ?> holder) ...
Ahora holder.comparator
es un Comparator
y un Comparator
. No me queda claro exactamente cuántos problemas le causaría esto al compilador, pero claramente no es bueno. Supongamos en particular que Comparator
tenía un método como este:
void sort(List extends T> list);
Nuestro Comparator
/ Comparator
híbrido ahora tiene dos métodos con el mismo borrado:
void sort(List extends Integer> list); void sort(List extends String> list);
Es por este tipo de razones que no puede especificar un tipo de este tipo directamente:
& Comparator > void bar() ...
java.util.Comparator cannot be inherited with different arguments:and
Ya que >
le permite hacer lo mismo indirectamente, también está descartado.
Aquí hay otra cita de JLS:
La forma de un límite está restringida (solo el primer elemento puede ser una variable de clase o tipo, y solo puede aparecer una variable de tipo en el límite) a impedir que surjan ciertas situaciones incómodas.
¿Qué son exactamente esas situaciones incómodas? No lo sé.
Si guardas algún reparo y capacidad de enriquecer nuestro enunciado te invitamos ejecutar un paráfrasis y con placer lo observaremos.