tipos formales acotados

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)