比较 VS <?扩展比较>
Comparable VS <? extends Comparable>
关于以下代码:
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"不会编译?
提前致谢。
因为
List<String> lst = Array.asList("abc","def");
lst
列表具有通用类型 String
,而不是 Comparable
。
String
class,然而,实现 Comparable<String>
接口,所以它适合 ? extends Comparable
通用类型。
这是因为 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 作为基数的列表 class(例如 List<Comparable>
、List<String>
、List<Integer>
, 等等)
要更正确地定义您的函数,您应该执行以下操作:
public static <T extends Comparable<T>> boolean func(List<T> lst) {}
这强制该类型可与自身进行比较。您的函数比较列表中的第一个和第二个元素,因此最好确保列表中的每个元素实际上都可以与其他所有元素进行比较。
发生这种情况是因为泛型 不变 。即使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) {
.....
}
关于以下代码:
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"不会编译?
提前致谢。
因为
List<String> lst = Array.asList("abc","def");
lst
列表具有通用类型 String
,而不是 Comparable
。
String
class,然而,实现 Comparable<String>
接口,所以它适合 ? extends Comparable
通用类型。
这是因为 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 作为基数的列表 class(例如 List<Comparable>
、List<String>
、List<Integer>
, 等等)
要更正确地定义您的函数,您应该执行以下操作:
public static <T extends Comparable<T>> boolean func(List<T> lst) {}
这强制该类型可与自身进行比较。您的函数比较列表中的第一个和第二个元素,因此最好确保列表中的每个元素实际上都可以与其他所有元素进行比较。
发生这种情况是因为泛型 不变 。即使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) {
.....
}