关于以下代码:
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”会不会编译?
提前致谢。
这是因为泛型是不变的。即使String
是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) {
.....
}
这是因为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) {}
这强制该类型与其自身相当。您的函数会比较列表中的第一个和第二个元素,因此最好确保列表中的每个元素实际上与其他元素相当。
因为
List<String> lst = Array.asList("abc","def");
lst
列表有通用类型String
,而不是Comparable
。 String
类,hovewer,实现Comparable<String>
接口,因此它适合? extends Comparable
泛型类型。