Existiendo tipos
y métodos genéricos, los métodos pueden recibir o devolver objetos de dichos
tipos.
String ultima(List<String>
lista) {
return lista.get(lista.size() - 1);
}
donde el
compilador puede chequear que llamamos al método con una lista de String.
Curiosamente,
java no admite en estos casos las tradicionales relaciones de herencia, sino
que es necesario ajustarse exactamente a lo dicho. En el ejemplo anterior,
String significa única y exclusivamente String, no siendo aceptable subtipos de
dicha clase.
NOTA: El uso tradicional de la herencia dice que donde se admite un tipo T
es posible emplear cualquier subtipo de T.
A fin de
generalizar, java introduce una notación específica para aliviar dicha rigidez:
<T>
acepta el tipo T y nada más que el tipo T
<? extends T>
acepta el tipo T o cualquier subtipo de T. En particular, <?> acepta cualquier tipo.
<? super T>
acepta el tipo T o cualquier supertipo de T.
Esta flexibilidad
se puede usar allá donde hay tipos formales o argumentos formales:
class
X<? extends T> { ... }
es un tipo genérico que sólo puede instanciarse con subtipos de T.
void metodo(List<? extends T> lista) { ... }
es un método que sólo puede llamarse con listas de objetos que son subtipos
de T.
void metodo(Pareja<?, ?> pareja)
es un método que admite cualquier pareja de datos de cualquier tipo.
Temas relacionados
83. Genéricos [generics] (concepto)