【问题标题】:Why objects are not same added to hashset with same value, even hashCode and equals are overriden为什么对象不一样添加到具有相同值的哈希集中,甚至 hashCode 和 equals 被覆盖
【发布时间】:2015-09-07 20:00:28
【问题描述】:

这是生成哈希集大小 3 而不是 2 的代码

package dump.test;
import java.util.*;
public class WrappedString {
    private String s;
    public WrappedString(String s) { this.s = s; }
    public static void main(String[] args) {
        HashSet<Object> hs = new HashSet<Object>();
        WrappedString ws1 = new WrappedString("aardvark");
        WrappedString ws2 = new WrappedString("aardvark");
        String s1 = new String("aardvark");
        String s2 = new String("aardvark");
        hs.add(ws1); hs.add(ws2); hs.add(s1); hs.add(s2);
        System.out.println(hs.size()+hs.toString()); 
    }
    public boolean equals(Object aSong) {
        String s = aSong.toString();
        System.out.println(s);
        return s.equals(this.s);
    }
    public int hashCode() {
        System.out.println(this.s + "-" + this.s.hashCode());
        return this.s.hashCode();
    }
    /*public int compareTo(Object aSong) {
        String s = aSong.toString();
        return this.s.compareTo(s);
    }*/
}

如果 equals 和 hashCode 被覆盖,它总是在输出下方打印

您可以看到两个对象在输出中具有相同的代码,但计为不同,生成的计数为 3

如果我们不覆盖 equals 和 hashCode

请帮助我这是如何工作的。

【问题讨论】:

  • 您的 equal 方法甚至不会为 ws1.equals(ws2) 返回 true

标签: java equals hashcode hashset


【解决方案1】:

问题是您的情况不是对称的。如果实现决定在 String 实例上调用 equals 并将您的类作为参数,它肯定会返回 false,因此您的代码将不会总是有效。

【讨论】:

  • 感谢塞巴斯蒂安!哪些努力可以使上面在代码中创建的两个 WrappedString 对象是相同的。我想在上面的代码中产生计数为 2。
  • 添加 public String toString() { return this.s; } 消除了我的困惑。
【解决方案2】:

来自 Set 接口的 JavaDoc:

不包含重复元素的集合。更正式地说,集合不包含一对元素 e1 和 e2 使得 e1.equals(e2),并且最多包含一个空元素。正如它的名字所暗示的,这个接口模拟了数学集合抽象。

所以,HashSet 在添加新元素之前会检查 equals(Object)。由于第二个字符串等于第一个字符串,所以它没有被添加。在您的WrappedString 上,您没有覆盖equals(Object),因此,您使用的是从Object 继承的那个,它只检查对象ID(在您的情况下为659e0bfd2a139a55)。

【讨论】:

  • 感谢 jpkrohling!如果它遇到对象 ID 2fcf3776(根据第一张图像)怎么办?所以我认为两个 ID 都是相同的,equals 会发现值太相同,它会在集合中添加为一个,但事实并非如此。哪些努力可以使上面在代码中创建的两个 WrappedString 对象是相同的。我想在上面的代码中产生计数为 2。
  • 事实上,我的回答并不是 100% 正确,因为 Object 会比较对象的内部 ID。为了让您的代码正常工作,我想说您需要让 WrappedString#equals 来比较内部字符串并让您的 toString 返回底层字符串。
  • 感谢 jpkrohling!它像你说的那样工作。我需要重写另一个工厂方法 toString 并使其返回底层字符串值。以前它无法正确地从对象转换为字符串,并且尽管具有相同的对象 ID,但可能会导致不同的对象。以下小 sn-p 作品: public String toString() { return this.s; }
【解决方案3】:

添加

public String toString() { return this.s; }

消除了我的困惑。以前它无法将真值从转换对象转换为字符串,需要重写 toString 以返回底层值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-22
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多