2011-05-31 38 views
16

有什么方法可以覆盖Set数据类型使用的equals方法吗?我为一个叫Fee的类写了一个自定义的equals方法。现在我有的Fee,我想确保没有重复的条目。因此,我正在考虑使用中的Set,但决定两个费用是否相等的标准存在于Fee类中的覆盖equals方法中。Java集合集合 - 覆盖等于方法

如果使用LinkedList,我将不得不遍历每一个列表项,并呼吁在Fee类重写equals方法与其余条目作为参数。仅仅阅读它听起来太多了,并且会增加计算复杂度。

我可以使用Set和覆盖的equals方法吗?我是不是该?

回答

3

Set使用添加到集合中的对象的equals方法。 JavaDoc状态

一个不包含重复元素的集合。更正式地,集合不包含e1和e2这样的元素对,使得e1.equals(e2)和至多一个空元素。

Set.equals()方法仅用于比较两组之间是否相等。它从未用作添加/删除集合中的项目的一部分。

-1

有PredicatedList或PredicatedSet在Apache Commons Collection

+1

你能详细说明这是如何回答OP吗?我正在寻找一种方法来忽略大写/小写'Set .contains(“foo”)' – 2014-07-16 08:49:28

30

杰夫福斯特说:

的Set.equals()方法仅用于比较两个组的相等性。

可以使用Set摆脱重复条目,但要注意:HashSet不使用其包含的对象equals()方法来确定的平等。

HashSet一个携带有内部HashMap<Integer(HashCode), Object>条目,并使用equals()方法以及在的HashCode的equals方法来确定平等。要解决这个问题

的一种方法是重写hashCode()在你把设置类,所以它代表你equals()标准

例如:

class Fee { 
     String name; 

    public boolean equals(Object o) { 
     return (o instanceof Fee) && ((Fee)o.getName()).equals(this.getName()); 
    } 

    public int hashCode() { 
     return name.hashCode(); 
    } 

} 
+4

'HashSet'遵循'Set'合同,它需要使用equals()方法来确定相等性。但是它利用了这样一个事实:如果Object的equals()是另一个对象,那么它需要具有相同的'hashCode()'。你可以**在单个'HashSet'中有多个具有相同'hashCode()'值的对象。 – Martin 2013-11-14 21:25:15

+0

好点马丁。我只是在一个小测试应用程序中进行了验证。如果添加一个既不等于NOR的对象又具有与set-objects相同的hashCode,则它将作为新对象添加。我在我的回答中澄清了这一点。 – 2013-12-02 12:55:25

6

可以和应该使用一个Set用来保存一个覆盖了equals方法的对象类型,,但你也可能需要重写hashCode()。等号对象必须具有相同的散列码。

例如:

public Fee{ 

    public String fi; 

    public String fo; 

    public int hashCode(){ 

     return fi.hashCode()^fo.hashCode(); 
    } 

    public boolean equals(Object obj){ 

     return fi.equals(obj.fi) && fo.equals(obj.fo); 
    } 
} 

(根据需要与null检查,当然。)

集经常使用的hashCode(),以优化性能,并会表现不好,如果你的hashCode方法被破坏。例如,HashSet uses an internal HashMap.

If you check the source code of HashMap,你会看到它取决于两个的hashCode()和equals()方法的元素的方法来确定的平等:

if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 

如果没有正确生成散列,你的equals方法可能永远不会被调用。

为了让您的设置更快,您应该尽可能为不相等的对象生成不同的哈希码。

+2

我知道这是一个例子,但不应该使用连接来生成hashCode。就像你说的那样,hashCode方法可能会经常被调用,并且字符串连接是一个缓慢而昂贵的操作。 更好的方法是简单地异或字符串hashCode。例如:'return fi.hashCode()^ fo.hashCode();' 此外,你的'equals()'方法有点过分杀死。 你不需要将'fi'与'fo'进行比较,然后将'fo'与'fi'进行比较。 Object' Javadoc明确说明'equals()'方法必须是对称的。因此,只有performin'fi.equals(fo)'就足够了(忽略'null')。 – Moinonime 2013-07-16 20:01:21

+0

感谢Mathieu。我编辑了我对XOR散列码的回答,而不是连接字符串。我不认为你对等号方法的评论是有效的。 fi.equals(fo)将完全不同,并且与我定义的hashCode方法不一致。 – SharkAlley 2013-07-20 07:17:09

1

一个解决方案是使用带比较器的TreeSet

从文档:被认为等于通过该方法

TreeSet实例使用其的compareTo执行所有元件比较(或比较)的方法,因此两个元件,从所述一组,相等的观点出发。

这种方法比使用LinkedList快得多,但比HashSet(ln(n)vs n)慢一点。

值得注意的是使用TreeSet的一个副作用是你的集合被排序。