在 this answer ,我试图解释为什么 Collection 方法 add
具有签名 add(E)
而 remove
是 remove(Object)
.我想出了正确的签名应该是
public boolean remove(? super E element)
由于这在 Java 中是无效语法,因此他们必须坚持使用 Object
,而它恰好是 super E
(E
的父类(super class)型) >) 对于任何 E
。以下代码解释了为什么这是有意义的:
List<String> strings = new ArrayList();
strings.add("abc");
Object o = "abc"; // runtime type is String
strings.remove(o);
由于运行时类型是 String,因此成功。如果签名是remove(E)
,这会在编译时导致错误,但不会在运行时导致错误,这是没有意义的。但是,以下应该在编译时引发错误,因为该操作因其类型而注定会失败,而这些类型在编译时是已知的:
strings.remove(1);
remove
采用 Integer
作为参数,它不是 super String
,这意味着它可以永远不要真正从集合中删除任何内容。
如果 remove
方法是使用参数类型 定义的? super E
,编译器可以检测到类似上述情况。
问题:
我的理论是否正确,即 remove
应该有一个逆变 ? super E
参数而不是 Object
,这样编译器就可以过滤掉上面示例中所示的类型不匹配? Java 集合框架的创建者选择使用 Object
而不是 是否正确? super E
因为 ? super E
会导致语法错误,他们只是同意使用 Object
而不是 super
,而不是使通用系统复杂化?
此外,removeAll
的签名应该是
public boolean removeAll(Collection<? super E> collection)
<小时/>
请注意,我不想想知道为什么签名不是remove(E)
,这在 this question 中被询问和解释。 。我想知道 remove
是否应该是逆变的(remove(? super E)
),而 remove(E)
表示协方差。
此方法不起作用的一个示例如下:
List<Number> nums = new ArrayList();
nums.add(1);
nums.remove(1); // fails here - Integer is not super Number
重新考虑我的签名,它实际上应该允许 E
的子和父类(super class)型。
最佳答案
这是一个错误的假设:
because the operation is bound to fail because of its types, which are known at compile-time
这与 .equals
接受对象的道理相同:对象不一定需要具有相同的类才能相等。考虑这个具有 List 不同子类型的示例,如 the question @Joe linked 中指出的。 :
List<ArrayList<?>> arrayLists = new ArrayList<>();
arrayLists.add(new ArrayList<>());
LinkedList<?> emptyLinkedList = new LinkedList<>();
arrayLists.remove(emptyLinkedList); // removes the empty ArrayList and returns true
使用您提议的签名是不可能实现这一点的。
关于java - 应该删除(Object) 为删除(? super E),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30784598/