Java 为自定义类实现hashcode和equals

Java 为自定义类实现hashcode和equals,java,equals,hashcode,abstract-data-type,custom-object,Java,Equals,Hashcode,Abstract Data Type,Custom Object,所以我有很多自定义类,它们内部也有自定义类,使用组合 我的自定义类有经常更改的变量,我将它们添加到hashset中。所以我的问题是何时实现hashCode -对于一个只有不断变化的私有字段的类,我应该怎么做 下面是一个自定义类的示例: public class Cell { protected boolean isActive; protected boolean wasActive; public Cell() { this.isActive = false;

所以我有很多自定义类,它们内部也有自定义类,使用组合

我的自定义类有经常更改的变量,我将它们添加到hashset中。所以我的问题是何时实现hashCode -对于一个只有不断变化的私有字段的类,我应该怎么做

下面是一个自定义类的示例:

public class Cell {
    protected boolean isActive;
    protected boolean wasActive;

    public Cell() {
    this.isActive = false;
    this.wasActive = false;
    }

    // getter and setter methods...

    @Override
    public int hashCode() {
    // HOW SHOULD I IMPLEMENT THIS IF THIS custom object is constantly
        // being added into HashSets and have it's private fields isActive
        // and wasActive constantly changed.
    }

    // ANOTHER QUESTION Am I missing anything with this below equals implementation?
    @Override
    public boolean equals(Object object) {
    boolean result = false;
    if (object instanceof Cell) {
        Cell otherCell = (Cell) object;
        result = (this.isActive == otherCell.isActive && this.wasActive == 
            otherCell.wasActive);
    }
    return result;
    }

下面是具有私有字段的类的示例

public class Test {

    private int num;
    private String data;

    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if ((obj == null) || (obj.getClass() != this.getClass()))
            return false;
        // object must be Test at this point
        Test test = (Test) obj;
        return num == test.num
                && (data == test.data || (data != null && data
                        .equals(test.data)));
    }

    public int hashCode() {
        int hash = 7;
        hash = 31 * hash + num;
        hash = 31 * hash + (null == data ? 0 : data.hashCode());
        return hash;
    }

}
Java中的Equals和hashCode契约: 当我们重写equals()方法时,必须重写hashCode(),Java中的equals方法必须遵循它与Java中的hashCode方法的约定,如下所述

  • 如果两个对象通过equals()方法相等,则必须有hashcode 保持一致
  • 如果equals()方法不等于两个对象,则不存在哈希代码 可能相同,也可能不同
  • 以下是类的equals和hashcode方法的示例实现:

     //Hashcode Implementation    
    
       @Override
        public int hashCode() 
        {
            final int prime = 31;
            int result = 1;
            result = prime * result + (isActive ? 1231 : 1237);
            result = prime * result + (wasActive ? 1231 : 1237);
            return result;
        }
    
    //equals Implementation    
        @Override
        public boolean equals(Object obj) 
        {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Cell other = (Cell) obj;
            if (isActive != other.isActive)
                return false;
            if (wasActive != other.wasActive)
                return false;
            return true;
        }
    

    你是索尔。在标准Java集合的键中使用hashCode()时,它不应更改。或者,您需要一个自定义的HashSet类实现

    仅使用不改变的字段(或者,如果您大胆且不介意偶尔崩溃,则很少改变字段)来计算hashCode()

    (补充)。在您的特定示例中,使用Object.hashCode()


    (添加了#2)即使您的Cell类是不可变的(两个布尔值没有改变),它对于散列也是一个糟糕的选择,因为它只有2位的范围。想象一下,根据男性/女性和蓝眼睛/棕色眼睛对所有人进行分类。这是一个很好的开始,但只有4个类别,每个类别大约有20亿人。理想情况下,您可以有其他几个类别,如出生年份、出生国等。

    我猜,仅基于两个布尔变量,hashcode无法唯一生成。您需要在类中添加一些其他变量。例如,单元的x和y坐标(只是一个示例)。我猜这不是类的全部代码。请注意,如果您使用Cell作为映射中的键,那么只有这样,哈希集合才会知道更改的哈希代码,因此才会产生问题。因此,一旦将对象添加为哈希集合中的键,其哈希代码就不能更改。您可以为单元格保留一些唯一标识符并将其用作键。这取决于您在哈希集中搜索的内容。您是在搜索一个特定的对象,在这种情况下没有实现hashCode或equals,还是在搜索一个具有特定状态的对象,在这种情况下,您使用感兴趣的状态变量实现hashCode和equals。不应将不断变化的字段用于hashCode函数,否则对象将“丢失”。要正确实现hashCode和equals,我建议您阅读joshua在《有效java》中的hashCode和equals部分。他已经详细解释了这里很难解释的事情。
    你不能用布尔值实现hascode。
    你可以,但它看起来可能不好看。是的,你是莱特。但是使用布尔值创建哈希代码是没有用的。您认为这会有什么帮助?我的意思是,您正在hashcode中使用可变字段。现在,如果单元格对象用作哈希集合中的键,并且在HashMap中输入时这两个字段都为true,那么现在字段会发生变化,hashcode也会发生变化!如果您现在尝试基于该对象查找某个对象,HashMap将在另一个bucket而不是原始bucket中查找,您将找不到该对象。@NarendraPathai:如果具有可变字段的对象的特定实例永远不会暴露于会改变该字段的代码中,那么该实例的字段真的是可变的吗?将散列依赖于可变字段的对象存储到散列集合中的代码必须确保存储在集合中的对象不会暴露于任何可能导致其散列在散列集合中时发生更改的代码中。通常,提供这种保证的最简单方法是使对象不可变,但在某些情况下,它可能更实用……避免将对象实例暴露于任何不知道其所存储的哈希集合的情况下,并确保任何更改实例的请求都将从集合中删除未更改的实例,然后进行更改,然后将更改后的实例重新添加到集合中。与尝试实现自己的hashCode()方法不同,您应该尽可能使用现有的标准实现,例如用于字符串的实现。为此,首先为对象实现toString()。然后,可以使用toString().equals()构建对象的equals()方法,而对象的hashCode()方法可以返回这个.toString().hashCode()。