Java:重复对象被添加到集合中?

20
如果我运行以下代码,输出结果是2,这意味着该集合包含2个元素。然而,根据hashcode()值以及.equals()方法,这两个对象都是相等的,因此我认为该集合应该只含有1个元素。 我的理解中似乎存在一些明显的错误?
package HELLO;

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

public class Test {

    public static void main(String[] args) throws Exception {
        Set<Alpha> s = new HashSet<Alpha>();
        Alpha a1 = new Alpha();
        Alpha a2 = new Alpha();
        s.add(a1);
        s.add(a2);
        System.out.println(s.size());
    }
}   

class Alpha {
    int a = 10;

    public int hashcode() {
        return a;
    }

    public boolean equals(Object obj) {
        return (obj instanceof Alpha && ((Alpha) obj).a == this.a);
    }

    public String toString() {
        return "Alpha : " + a;
    }
}
3个回答

36

你的哈希code方法没有覆盖Object类的hashCode方法,因此你的equals方法违反了契约,因为它与hashCode结果不一致,这样你就可能有相等但具有不同哈希码的对象。

记住:当重写方法时,应始终使用@Override注释,因为这将帮助你捕获此类错误。

@Override  // ** don't forget this annotation
public int hashCode() { // *** note capitalization of the "C"
  return a;
}

此外,您需要改进代码格式,特别是在此处发布代码供我们审查时。如果符合标准(这就是为什么标准存在的原因),我们将能够更好地理解您的代码并帮助您。因此,请尝试使同一块中缩进的所有代码行保持缩进一致,并确保基本级别的代码(包括导入、外部类声明及其结束大括号)左对齐。
import java.util.HashSet;
import java.util.Set;

public class Test {

   public static void main(String[] args) throws Exception {
      Set<Alpha> s = new HashSet<Alpha>();
      Alpha a1 = new Alpha();
      Alpha a2 = new Alpha();
      s.add(a1);
      s.add(a2);
      System.out.println(s.size());
   }
}

class Alpha {
   int a = 10;

   @Override
   public int hashCode() {
      return a;
   }

   public String toString() {
      return "Alpha : " + a;
   }

   @Override
   public boolean equals(Object obj) {
      if (this == obj)
         return true;
      if (obj == null)
         return false;
      if (getClass() != obj.getClass())
         return false;
      Alpha other = (Alpha) obj;
      if (a != other.a)
         return false;
      return true;
   }
}

如果要进行深入阅读,请看这篇精彩的文章:在Java中覆盖equals和hashCode方法


谢谢!我再也不会忘记使用 @Override 了 :) - snow_leopard
@snow_leopard:养成这个习惯是非常好的。祝你好运! - Hovercraft Full Of Eels
除了"@Override"之外,我还必须在equals函数中添加一行代码,否则集合无法检测到重复项,并且始终包含具有相同内容的对象多次:if(this.hashCode() == msg.hashCode()) return true; - Sven Jung
1
@sven:我强烈反对你的那行代码,因为它完全违反了equals和hashCode协定所规定的内容。你需要那行代码的原因可能是你的equals方法存在其他问题。 - Hovercraft Full Of Eels
1
@hoverkraft:你说得对,我的equals()方法中有一个错误,在错误的情况下返回了false,导致出现了多个条目。在equals()方法中检查哈希值是一个坏主意。 - Sven Jung

4
"@Overrides"注解的作用是覆盖超类中同名方法。
@Override
public int hashCode() {
    return a;
}

@Override
public boolean equals(Object obj) {
    return (obj instanceof Alpha && ((Alpha) obj).a == this.a);

}

@Override
public String toString() {
    return "Alpha : " + a;
}

4

你的方法hashcode应该命名为hashCode(大写字母“C”)。

如果您计划重写方法,应使用@Override注释。

如果您使用了该注释,您会注意到问题,因为代码将无法编译。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接