为什么不';Java集合是否删除泛型方法?
为什么不是通用的 似乎为什么不';Java集合是否删除泛型方法?,java,api,generics,collections,Java,Api,Generics,Collections,为什么不是通用的 似乎集合可以有布尔删除(EO) 然后,当您不小心尝试从集合中删除(例如)Set而不是每个字符串时,这将是一个编译时错误,而不是以后的调试问题。因为如果您的类型参数是通配符,则不能使用通用的删除方法 我似乎记得在使用Map的get(Object)方法时遇到过这个问题。在这种情况下,get方法不是泛型的,尽管它理应被传递给与第一个类型参数相同类型的对象。我意识到,如果你用一个通配符作为第一个类型参数来传递映射,那么如果这个参数是泛型的,那么就没有办法用这个方法从映射中获取元素。不能
集合
可以有布尔删除(EO)代码>
然后,当您不小心尝试从集合中删除(例如)Set
而不是每个字符串时,这将是一个编译时错误,而不是以后的调试问题。因为如果您的类型参数是通配符,则不能使用通用的删除方法
我似乎记得在使用Map的get(Object)方法时遇到过这个问题。在这种情况下,get方法不是泛型的,尽管它理应被传递给与第一个类型参数相同类型的对象。我意识到,如果你用一个通配符作为第一个类型参数来传递映射,那么如果这个参数是泛型的,那么就没有办法用这个方法从映射中获取元素。不能真正满足通配符参数,因为编译器不能保证类型正确。我推测add是泛型的原因是,在将其添加到集合之前,您需要保证类型是正确的。但是,当删除对象时,如果类型不正确,那么它无论如何都不会匹配任何内容。如果参数是通配符,则该方法将无法使用,即使您可能有一个可以保证属于该集合的对象,因为您在前一行中刚刚获得了对该对象的引用
我可能没有很好地解释它,但对我来说它似乎足够合乎逻辑。Remove不是一个泛型方法,因此使用非泛型集合的现有代码仍然可以编译,并且仍然具有相同的行为
有关详细信息,请参阅
编辑:评论员询问为什么add方法是泛型的。[…删除了我的解释…]第二位评论员回答firebird84的问题比我好得多。因为它会破坏现有(Java5之前)代码。e、 g
Set stringSet = new HashSet();
// do some stuff...
Object o = "foobar";
stringSet.remove(o);
现在您可能会说上面的代码是错误的,但是假设o来自一组异构对象(即,它包含字符串、数字、对象等)。您希望删除所有匹配项,这是合法的,因为remove只会忽略非字符串,因为它们不相等。但如果您将其删除(字符串o),则该操作将不再有效 我一直认为这是因为remove()没有理由关心你给它什么类型的对象。不管怎样,检查该对象是否是集合包含的对象之一非常容易,因为它可以对任何对象调用equals()。有必要检查add()上的类型,以确保它只包含该类型的对象。Josh Bloch和Bill Pugh在中提到了这个问题
Josh Bloch说(6:41),他们试图泛化get方法
地图,删除方法和其他一些,但“它根本没有工作”
有太多合理的程序,如果
您只允许集合的泛型类型作为参数类型。
他给出的例子是编号的列表
与
List
ofLong
s.除了其他答案之外,还有另一个原因说明该方法应该接受一个对象,即谓词。考虑以下样本:
class Person {
public String name;
// override equals()
}
class Employee extends Person {
public String company;
// override equals()
}
class Developer extends Employee {
public int yearsOfExperience;
// override equals()
}
class Test {
public static void main(String[] args) {
Collection<? extends Person> people = new ArrayList<Employee>();
// ...
// to remove the first employee with a specific name:
people.remove(new Person(someName1));
// to remove the first developer that matches some criteria:
people.remove(new Developer(someName2, someCompany, 10));
// to remove the first employee who is either
// a developer or an employee of someCompany:
people.remove(new Object() {
public boolean equals(Object employee) {
return employee instanceof Developer
|| ((Employee) employee).company.equals(someCompany);
}});
}
}
班级人员{
公共字符串名称;
//覆盖等于()
}
类雇员扩展个人{
上市公司;
//覆盖等于()
}
类开发人员扩展了Employee{
公众经验;
//覆盖等于()
}
课堂测试{
公共静态void main(字符串[]args){
集合remove()
(在Map
以及Collection
中)不是通用的,因为您应该能够将任何类型的对象传入remove()
。移除的对象不必与传入remove()的对象类型相同
;它只要求它们相等。从remove()
的规范中,remove(o)
删除对象e
,以便(o==null?e==null:o.equals(e))
为true
。请注意,没有任何东西要求o
和e
为同一类型。这是因为equals()
方法将对象
作为参数,而不仅仅是对象的同一类型
尽管许多类通常都定义了equals()
,以便其对象只能等于其自己类的对象,但情况并非总是如此。例如,List.equals()的规范
说,如果两个列表对象都是列表并且具有相同的内容,那么它们是相等的,即使它们是List
的不同实现。因此回到这个问题中的示例,有一个Map
并调用remove()
使用LinkedList
作为参数,它应该删除具有相同内容的列表的键。如果remove()
是泛型的,并且限制了它的参数类型。假设有一个Cat
的集合,以及一些类型为Animal
、Cat
、siamescat
和Dog
的对象引用。询问集合是否包含Cat
或siamescat
引用的对象引用似乎是合理的。询问它是否包含动物
引用所引用的对象似乎是不可靠的,但它仍然是完全合理的。所讨论的对象可能毕竟是猫
,并且可能出现在集合中
此外,即使对象恰好不是一个Cat
,也可以确定它是否出现在集合中——只需回答“不,不是”。某种类型的“查找样式”集合应该能够有意义地接受任何superty的引用
public interface A {}
public interface B {}
public class MyClass implements A, B {}
public static void main(String[] args) {
Collection<A> collection = new ArrayList<>();
MyClass item = new MyClass();
collection.add(item); // works fine
B b = item; // valid
collection.remove(b); /* It works because the remove method accepts an Object. If it was generic, this would not work */
}