如何包含Set集合的方法

时间:2013-06-14 08:34:01

标签: java collections

嗨,我是java的新手,因为我知道set collection不会重复,当contains已经存在于collection中时,它的contains方法应该返回true。我试图在程序下运行,但我得到了意想不到的结果。

public class UserDefinedName {
    private final String first, last;

    public UserDefinedName(String first, String last) {
        this.first = first;
        this.last = last;
    }

    public boolean equals(Object o) {
        if (!(o instanceof UserDefinedName))
            return false;
        UserDefinedName n = (UserDefinedName) o;
        return n.first.equals(first) && n.last.equals(last);
    }

    public static void main(String[] args) {
        Set<UserDefinedName> s = new HashSet<UserDefinedName>();
        s.add(new UserDefinedName("Carballo", "Videl"));
        System.out.println(s.contains(new UserDefinedName("Carballo", "Videl")));
    }
}

我期待输出 true ,但程序打印 false 。 我做错了什么?

5 个答案:

答案 0 :(得分:8)

表单java doc

  

如果两个对象根据equals(Object)方法相等,那么   必须在两个对象中的每一个上调用hashCode方法   相同的整数结果。

如果hashCode()方法没有覆盖,则使用Object的hashCode()方法,这是默认实现。

在你的情况下,你有覆盖equals方法,但你使用hashCode()的默认实现,因为你没有覆盖UserDefinedName类中的hashCode()方法。

  

UserDefinedName类重写equals方法和   hashCode契约要求相等的对象具有相同的哈希码。至   履行此合同,您必须随时覆盖hashCode   覆盖等于

添加以下代码,它将起作用。

public int hashCode() {
return 37 * first.hashCode() + last.hashCode(); 
}

答案 1 :(得分:1)

因为hashSet使用对象的哈希码值来存储它。因此,它要求您必须覆盖您自己的类中的方法hashCode。由于您没有覆盖它,因此它使用从对象类继承的hashCode方法。

来自对象类的哈希码是使用对象的内存地址计算的,即:

UserDefinedName p = new UserDefinedName("Carballo", "Videl");
System.out.println(p);
System.out.println(0x1e5e2c3);
System.out.println(p.hashCode());

输出:

UserDefinedName@1e5e2c3
31843011
31843011

所以如果你试过这个,你会看到它输出为true:

Set<UserDefinedName> s = new HashSet<UserDefinedName>();
UserDefinedName p = new UserDefinedName("Carballo", "Videl");
s.add(p);
System.out.println(s.contains(p));

现在,如果你想比较你的用户类correclty,你将不得不覆盖你的hashCode方法(你可以用eclipse生成它)来按字段生成hashCode你的对象。

如果您的班级使用此方法,则会为您提供的代码打印true。

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((first == null) ? 0 : first.hashCode());
        result = prime * result + ((last == null) ? 0 : last.hashCode());
        return result;
    }

答案 2 :(得分:1)

当你重写equals方法时,也总是覆盖hashcode方法。 一个简单的规则是,如果两个对象被认为是相等的,那么它们应该返回相同的哈希码。

我接受了你的代码并在eclipse的帮助下生成了equals和hashcode

import java.util.HashSet;
import java.util.Set;

public class UserDefinedName {
private final String first, last;

public UserDefinedName(String first, String last) {
    this.first = first;
    this.last = last;
}

public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((first == null) ? 0 : first.hashCode());
    result = prime * result + ((last == null) ? 0 : last.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    UserDefinedName other = (UserDefinedName) obj;
    if (first == null) {
        if (other.first != null)
            return false;
    } else if (!first.equals(other.first))
        return false;
    if (last == null) {
        if (other.last != null)
            return false;
    } else if (!last.equals(other.last))
        return false;
    return true;
}

public static void main(String[] args) {
    Set<UserDefinedName> s = new HashSet<UserDefinedName>();
    s.add(new UserDefinedName("Carballo", "Videl"));
    System.out.println(s.contains(new UserDefinedName("Carballo", "Videl")));
    UserDefinedName obj1 = new UserDefinedName("prasad", "kharkar");
    UserDefinedName obj2 = new UserDefinedName("prasad", "kharkar");

    System.out.println(obj1.equals(obj2));
    System.out.println(obj1.hashCode());
    System.out.println(obj2.hashCode());

    }
}

输出

true
true
-1072813416
-1072813416

答案 3 :(得分:0)

除了equals之外,还需要实现hashcode()方法。

HashSet是一种在内部使用HashMap的数据结构。在HashMap中,对象存储在键值对中。但是,HashSet只接受键,相应的值是一个空的虚拟对象(这是由JVM负责的)。现在,要使此散列机制正常工作,您需要实现equals()以及hashCode()方法。根据{{​​3}}:

  

此类实现Set接口,由哈希表支持   (实际上是一个HashMap实例)。它不能保证   集合的迭代顺序;特别是,它并不保证   订单将随着时间的推移保持不变。该类允许null   元件。

     

此类为基本操作提供恒定的时间性能   (添加,删除,包含和大小),假设散列函数分散   桶中的元素正确。迭代这个集合   需要的时间与HashSet实例的大小之和成正比   (元素数量)加上后备HashMap的“容量”   实例(桶数)。

您可能想查看JDK documentation - 第二版 - 第三章 - 所有对象共有的方法“。这将使您清楚地了解实现equals()和hashCode()方法的最佳实践。 / p>

答案 4 :(得分:0)

HashSet需要覆盖hashCodeequals方法。