为什么HashSet 不会在contains()和remove()中限制E的参数类型

可能重复:
Map.get(Object key)不是(完全)generics的原因是什么
为什么Java的TreeSet remove(Object)不带E

为什么HashSet不限制E的参数类型:

public boolean contains(Object o) public boolean remove(Object o) 

就像它对add()一样

 public boolean add(E e) 

我的意思是如果编译器强制只添加类型E的对象,那么该集合不能包含/删除任何其他类型

不同之处在于添加必须是类型安全的以保持集合的完整性,而项目检查/删除可以提供“类型宽容”而不会有损害集合类型安全性的风险。 换句话说,如果添加错误类型的元素,该集将变为无效; 另一方面,如果你检查是否存在错误类型的元素,你只会得到一个false 。 同样适合remove :如果你传递一个不兼容类型的元素,它将不会在集合+中 ,所以删除将是一个无操作。


+除非你通过一个利用类型擦除的黑客入侵它。

然后该集不能包含/删除任何其他类型

当然可以。 阅读有关类型擦除或将HashSet转换为非genericsHashSet并向其添加不属于E类型的对象。

看看这段代码:

 Integer testInt = new Integer(3); // First, create a generic set of strings HashSet set = new HashSet(); set.add("abc"); // Then make it non-generic and add an integer to it ((HashSet) set).add(testInt); // Now your set-of-strings contains an integer! System.out.println(set); // prints: [abc, 3] // Remove the integer set.remove(testInt); System.out.println(set); // prints: [abc] 

这种奇怪的原因是generics类型的信息在运行时被删除,而您的集合变成一组简单的对象。

containsremove的参数不能限制在E因为你应该能够给它们提供相同的对象,这非常有用。 更准确地说, HashSet.remove的API说:

…更正式地,如果此集合包含这样的元素,则删除元素e(o == null?e == null:o.equals(e))。

Object.equalsObject作为参数,这对于启用不同类型之间的相等也非常有用。

因此,要启用containsremove的更一般function(在等价类而不是仅对象标识上),它们必须将Object作为参数。


例:

  HashSet> set = new HashSet>(); ArrayList list = new ArrayList(); list.add("foo"); LinkedList equalList = new LinkedList(); equalList.add("foo"); set.add(list); System.out.println(list.equals(equalList)); // prints: true System.out.println(set.contains(equalList)); // prints: true System.out.println(set); // prints: [[foo]] set.remove(equalList); System.out.println(set); // prints: [[]] 

您没有使用这两种方法向集合添加任何内容,因此不需要约束类型参数。 如果类型不匹配,则方法只能返回false。