Сравним VS <? расширяет Comparable> - PullRequest
       26

Сравним VS <? расширяет Comparable>

0 голосов
/ 07 сентября 2018

относительно следующего кода:

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;
    }
}

почему запись "? Extends Comparable" здесь будет компилироваться, а запись "Comparable" не будет компилироваться?

спасибо заранее.

Ответы [ 3 ]

0 голосов
/ 07 сентября 2018

Это потому, что List<SubClass> нельзя привести к List<BaseClass>. Давайте предположим, что это может

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

Это было бы проблемой, потому что целое число 5 не является String и не должно быть помещено в List<String>.

Используя ? extends Comparable, вы говорите, что функция может принимать список всего, что имеет Comparable в качестве базового класса (например, List<Comparable>, List<String>, List<Integer> и т. Д.)

Для более правильного определения вашей функции вы должны сделать следующее:

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

Это означает, что тип сопоставим с самим собой. Ваша функция сравнивает первый и второй элемент в списке, поэтому лучше убедиться, что каждый элемент в списке фактически сопоставим с любым другим элементом.

0 голосов
/ 07 сентября 2018

Это происходит потому, что дженерики инвариантны . Даже если String равно a Comparable, что означает:

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

Общие из них не будут работать:

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

listC = listS; // will fail

И это не сработает, независимо от того, каковы отношения между Comparable и String.

Когда вы меняете определение этого метода на:

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

Говорят, что: Подстановочный знак с расширением-границей делает тип ковариантным.

Это означает, что:

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

listC = listS; // would work here

Или, проще говоря, это означает, что List<String> является подтипом из List<? extends Comparable>.

Сейчас нужно заплатить небольшую цену, потому что listC теперь является производителем элементов, что означает, что вы можете извлекать из него элементы, но не можете ничего в него вкладывать.

И вскоре после того, как вы это поймете, вы еще не закончили, потому что определение этого метода было бы совершенно правильным, если было бы написано так:

 public static <T extends Comparable<? super T>> boolean func(List<T> lst) {
      .....
 }
0 голосов
/ 07 сентября 2018

Потому что

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

lst список имеет универсальный тип String, а не Comparable. String класс, Hovewer, реализуйте Comparable<String> интерфейс, поэтому он подходит для ? extends Comparable универсального типа.

...