当前位置:  开发笔记 > 编程语言 > 正文

为什么Java Collections不删除泛型方法?

如何解决《为什么JavaCollections不删除泛型方法?》经验,为你挑选了5个好方法。

为什么Collection.remove(Object o)不是通用的?

似乎Collection可能有boolean remove(E o);

然后,当您意外地尝试Set从a中删除(例如)而不是每个单独的String时Collection,这将是编译时错误,而不是稍后的调试问题.



1> newacct..:

remove()(in in Map以及in Collection)不是通用的,因为你应该能够传入任何类型的对象remove().删除的对象不必与传入的对象的类型相同remove(); 它只要求它们是平等的.从本说明书中remove(),remove(o)将删除对象e,使得(o==null ? e==null : o.equals(e))true.请注意,没有任何要求oe相同的类型.这是因为该equals()方法接受Objectas参数,而不仅仅是与对象相同的类型.

虽然,通常equals()可以确定许多类已经定义,以便其对象只能等于其自己的类的对象,但情况肯定并非总是如此.例如,List.equals()如果两个List对象都是Lists并且具有相同的内容,则表示两个List对象相等的规范,即使它们是不同的实现List.所以回来的例子在这个问题上,可以有一个Map和我打电话给remove()一个LinkedList作为参数,并应删除这与相同内容的列表的关键.如果remove()是通用的并且限制其参数类型,则这是不可能的.


@MattBall:"其中T是声明类"但Java中没有这样的语法.`T`必须在类上声明为类型参数,而`Object`没有任何类型参数.没有办法让一个类型引用"声明类".
答案似乎是正确的,但不完整.它只能解释为什么他们没有对`equals()`方法进行泛化?我可以看到更多的好处来打字安全而不是这种"自由主义"的方法.我认为当前实现的大多数情况都是针对错误进入我们的代码而不是快乐这种`remove()`方法带来的灵活性.
我认为kellogs在说,如果均等是带有equals(Tother)的通用接口“ Equality <T>”。然后,您可能具有`remove(Equality <T> o)`和`o`只是可以与另一个`T`比较的对象。
@kellogs:"将'equals()`方法泛化'是什么意思?"

2> dmeister..:

Josh Bloch和Bill Pugh在Java Puzzlers IV中提到了这个问题:幻影参考威胁,克隆攻击和转变复仇.

Josh Bloch说(6:41)他们试图通过格式化get方法,删除方法和其他方法,但"它根本不起作用".

如果只允许集合的泛型类型作为参数类型,则有太多合理的程序无法生成.由他给出的例子是一个交叉点ListNumberS和 ListLong


实际上,它非常简单!如果add()接受了错误的对象,它将破坏集合.它将包含它不应该的东西!对于remove()或contains(),情况并非如此.
顺便说一下,这个基本规则 - 使用类型参数来防止对集合的实际损害 - 在整个库中绝对一致.
为什么add()可以采用类型化参数但remove()不能超出我的理解范围.Josh Bloch将成为收藏问题的最终参考.如果不尝试制作类似的集合实现并亲自查看,我可能会得到它.:( 谢谢.
@KevinBourrillion:我一直在使用仿制药多年(在Java和C#中),却没有意识到"实际损坏"规则甚至存在......但是现在我已经看到它直接表明它100%完美无缺.谢谢你的鱼!!! 除了现在我觉得有必要回去看看我的实现,看看是否有一些方法可以并因此应该去除.叹.
克里斯 - 阅读Java Generics Tutorial PDF,它将解释原因.
他们不能做`public interface List { boolean remove(E element); }?

3> Bob Gettys..:

因为如果您的类型参数是通配符,则不能使用通用的remove方法.

我似乎回想起使用Map的get(Object)方法遇到这个问题.在这种情况下,get方法不是通用的,尽管它应该合理地期望传递与第一个类型参数相同类型的对象.我意识到,如果您使用通配符作为第一个类型参数传递Maps,那么如果该参数是通用的,则无法使用该方法从Map中获取元素.通配符参数不能真正满足,因为编译器无法保证类型是正确的.我推测add的一般原因是你需要在将它添加到集合之前保证类型是正确的.但是,在删除对象时,如果类型不正确,则无论如何都不会匹配任何内容.

我可能没有很好地解释它,但它对我来说似乎合乎逻辑.


所以也许这是一件好事 - 通配符使得集合不可变!

4> Hosam Aly..:

除了其他答案之外,还有另一个原因Object,即该方法应该接受一个谓词.请考虑以下示例:

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 people = new ArrayList();
        // ...

        // 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);
        }});
    }
}

关键是传递给remove方法的对象负责定义equals方法.通过这种方式构建谓词变得非常简单.


这对我来说似乎是一种虐待
它是滥用,因为你的谓词对象违反了`equals`方法的契约,即对称性.只要您的对象满足equals/hashCode规范,remove方法就只绑定到它的规范,因此任何实现都可以自由地进行比较.此外,您的谓词对象不实现`.hashCode()`方法(不能始终如一地实现等于),因此remove调用将永远不会对基于Hash的集合(如HashSet或HashMap.keys())起作用.它适用于ArrayList是纯粹的运气.
该列表实现为`yourObject.equals(developer)`,如Collections API中所述:http://java.sun.com/javase/6/docs/api/java/util/Collection.html#remove(java .lang.Object)]
(我不是在讨论泛型类型的问题 - 之前已经解决了 - 只有你在这里使用equals for谓词.)当然HashMap和HashSet正在检查哈希码,而TreeSet/Map正在使用元素的排序.尽管如此,他们还是完全实现了`Collection.remove`,而没有违反合同(如果排序是一致的).并且一个变量的ArrayList(或者我认为是AbstractCollection),等于调用转换仍然可以正确地实现合同 - 如果它不能按预期工作则是你的错,因为你违反了`equals`合约.

5> supercat..:

假设一个人的集合Cat,和一些类型的对象引用Animal,Cat,SiameseCat,和Dog.询问集合是否包含由引用CatSiameseCat引用引用的对象似乎是合理的.询问它是否包含Animal引用引用的对象可能看起来很狡猾,但它仍然是完全合理的.毕竟,有问题的对象可能是a Cat,并且可能出现在集合中.

此外,即使对象恰好是a以外的东西Cat,也没有问题说它是否出现在集合中 - 简单地回答"不,它没有".某种类型的"查找样式"集合应该能够有意义地接受任何超类型的引用,并确定该对象是否存在于集合中.如果传入的对象引用是不相关的类型,则集合无法包含它,因此查询在某种意义上没有意义(它总是回答"否").尽管如此,由于没有任何方法可以将参数限制为子类型或超类型,因此最简单地接受任何类型并对类型与集合类型无关的任何对象回答"否"是最实际的.

推荐阅读
mobiledu2402851323
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有