Con respecto al siguiente código:

public class Test <T extends Comparable>{
    public static void main(String[] args){
        List<String> lst = Array.asList("abc","def");
        System.out.println(func(lst));
    }
    public static boolean func(List<**here**> lst){
        return lst.get(0).compareTo(lst.get(1)) == 0;
    }
}

¿por qué escribir "? extiende Comparable" aquí compilaría y escribir "Comparable" no compilaría?

Gracias de antemano.

4
Kinor 7 sep. 2018 a las 17:37

3 respuestas

La mejor respuesta

Esto sucede porque los genéricos son invariantes . Incluso si String es a Comparable, lo que significa:

String s = "";
Comparable c = s; // would work

Los genéricos de estos no funcionarían:

List<Comparable> listC = List.of();
List<String> listS = List.of();

listC = listS; // will fail

Y esto no funcionaría sin importar cuál sea la relación entre Comparable y String.

Cuando cambia la definición de ese método a:

public static boolean func(List<? extends Comparable> lst) {
    ...
}

Esto se dice que: el comodín con un límite extendido hace que el tipo sea covariante.

Esto significa que :

List<? extends Comparable> listC = List.of();
List<String> listS = List.of();

listC = listS; // would work here

O, en palabras más simples, significa que List<String> es un subtipo de List<? extends Comparable>.

Ahora hay que pagar un pequeño precio, porque listC ahora es un productor de elementos, lo que significa que puede sacar elementos de él, pero no puede poner nada en él.

Y bien después de comprender esto, aún no ha terminado, porque la definición de ese método sería completamente correcta, cuando se escribe así:

 public static <T extends Comparable<? super T>> boolean func(List<T> lst) {
      .....
 }
8
Eugene 7 sep. 2018 a las 15:17

Porque

List<String> lst = Array.asList("abc","def");

La lista lst tiene un tipo genérico String, no Comparable. String clase, hovewer, implementa la interfaz Comparable<String>, por lo que cabe en el tipo genérico ? extends Comparable.

0
Jakub Pogorzelski 7 sep. 2018 a las 14:53

Esto se debe a que List<SubClass> no se puede convertir a List<BaseClass>. Supongamos que pudiera

List<String> sList = new ArrayList<>();
List<Comparable> cList = (List<Comparable>) sList;
cList.add(5);

Esto sería un problema porque el número entero 5 no es un String y no debe colocarse en un List<String>.

Al usar ? extends Comparable estás diciendo que la función puede tomar una lista de cualquier cosa que tenga Comparable como clase base (por ejemplo, List<Comparable>, List<String>, List<Integer>, etc.)

Para definir más correctamente su función, debe hacer lo siguiente:

public static <T extends Comparable<T>> boolean func(List<T> lst) {}

Esto exige que el tipo sea comparable consigo mismo. Su función compara el primer y el segundo elemento de la lista, por lo que es mejor asegurarse de que cada elemento de la lista sea realmente comparable con cualquier otro elemento.

1
DragonAssassin 7 sep. 2018 a las 15:05