代码之家  ›  专栏  ›  技术社区  ›  cchampion

Java:从equals方法中省略数据成员

  •  1
  • cchampion  · 技术社区  · 14 年前
    public class GamePiece {
        public GamePiece(char cLetter, int nPointValue) {
            m_cLetter=cLetter;
            m_nPointValue=nPointValue;
            m_nTurnPlaced=0;    //has not been placed on game board yet.
        }
    
        public char GetLetter() {return m_cLetter;}
        public int GetPointValue() {return m_nPointValue;}
        public int GetTurnPlaced() {return m_nTurnPlaced;}
    
        public void SetTurnPlaced(int nTurnPlaced) { m_nTurnPlaced=nTurnPlaced; }
    
        @Override
        public boolean equals(Object obj) {
            /*NOTE to keep this shorter I omitted some of the null checking and instanceof stuff. */
            GamePiece other = (GamePiece) obj;
    
            //not case sensitive, and I don`t think we want it to be here.
            if(m_cLetter != other.m_cLetter) {
                return false;
            }
    
            if(m_nPointValue != other.m_nPointValue) {
                return false;
            }
            /* NOTICE! m_nPointValue purposely omitted.  It does not affect hashcode or equals */
    
            return true;
        }
    
        @Override public int hashCode() {
            /* NOTICE! m_nPointValue purposely omitted.  It should not affect hashcode or equals */
            final int prime = 41;
            return prime * (prime + m_nPointValue + m_cLetter);
        }
    
        private char m_cLetter;
        private int m_nPointValue;
        private int m_nTurnPlaced;//turn which the game piece was placed on the game board.  Does not affect equals or has code!
    }
    

    考虑给定的代码段。在引入m\u nTurnPlaced成员之前,这个对象是不可变的(可以通过setturnplacted方法修改,所以现在GamePiece是可变的)。

    GamePiece用于ArrayList,我调用contains和remove方法,它们都依赖于equals方法来实现。

    我的问题是,在Java中,一些成员不影响equals和hashcode可以吗?这将如何影响它在我的ArrayList中的使用?既然这个对象是可变的,那么使用哪种类型的java集合是不安全的?有人告诉我,不应该重写可变对象上的equals,因为它会导致某些集合的行为“奇怪”(我在java文档的某个地方读到过)。

    4 回复  |  直到 14 年前
        1
  •  1
  •   Barthelemy    14 年前

    注: 这个答案通常是关于可变对象的,即hashCode和equals方法依赖于可变成员值的对象。在您的例子中,GamePiece是可变的,但是equals和hashCode方法不受可变成员的影响。

    我的问题是,这样可以吗 成员不影响 哈希码?

    这是可以接受的做法,只要使用相同的成员计算equals和hashcode。

    一般来说,可变对象不会影响您对ArrayList的使用:您可以插入可变对象, ,使用索引访问可变对象, 获取(索引) 删除(索引)

    如果使用remove(object)和indexOf(object)方法删除或搜索对象,ArrayList将对ArrayList中的对象调用equals(),因此程序需要注意ArrayList中的对象在插入后可能已更改。这对于GamePiece来说不是问题,因为equals()方法不依赖于可变成员。

    它需要什么类型的java集合 现在使用此对象不安全

    只要检查一下 Collections API

    “注意:如果使用可变对象作为映射键,则必须非常小心。当对象是映射中的键时,如果对象的值以影响equals比较的方式更改,则不指定映射的行为。这项禁令的一个特例是,不允许地图将自身作为一把钥匙。虽然允许映射将自身包含为一个值,但还是要特别小心:equals和hashCode方法在这样的映射上已经没有很好的定义。”

        2
  •  2
  •   polygenelubricants    14 年前

    是的,当然你是怎么定义你的 equals hashCode

    BitSet bitset = new BitSet();
    Collection<BitSet> bitsetcol = new HashSet<BitSet>();
    bitsetcol.add(bitset);
    System.out.println(bitsetcol.contains(bitset)); // prints true
    bitset.set(42);
    System.out.println(bitsetcol.contains(bitset)); // prints false!!!
    

    这里发生的是 Bitset 定义 等于 哈希码 HashSet 使用查找对象 等于 bitset ,它现在有一个不同的 哈希码 bitsetcol 再也找不到了。

    你会注意到如果 bitsetcol = new ArrayList<BitSet>(); ,然后它仍然可以找到它!不同的 Collection


    @Override equals 对于可变类型,是的,这当然很好。 BitSet 当然可以。最重要的是,这正是你所期望的 位集合

    如果您的可变类 哈希码 ,然后这样做。

        3
  •  1
  •   Dolph    14 年前

    其中的一个好处是你可以自由地设计你的产品 .equals() .hashcode() 因为你的目标需要。

    .equals() 行为 非常一致 This article explains how to override these methods using best practices .

        4
  •  1
  •   Jack    14 年前

    平等具有你想要赋予它的意义。。

    在你的例子中,你的意思是 GamePiece 有不同的 m_nTurnPlaced 将被视为平等的对象。所以 是此对象的状态,不应在 equals(o) hashcode() .

    这是什么意思?

    • 当你改变时不会改变 打开
    • 当您在列表上使用add或remove时,您将考虑 GameState 正确:这实际上意味着你不能区分两个 GameStates 不同的 打开