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

发布于 2024-08-24 16:09:52 字数 1809 浏览 11 评论 0原文

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_nTurnPlaced 成员(可以通过 SetTurnPlaced 方法修改,所以现在 GamePiece 变得可变)。

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

我的问题是,Java 中某些成员不影响 equals 和 hashcode 是否可以或者是常见的做法?这将如何影响它在我的 ArrayList 中的使用?既然这个对象是可变的,那么使用什么类型的 java 集合是不安全的?有人告诉我,你不应该覆盖可变对象上的 equals,因为它会导致某些集合表现得“奇怪”(我在 java 文档中的某个地方读到了这一点)。

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!
}

Consider the given piece of code. This object has been immutable until the introduction of the m_nTurnPlaced member (which can be modified by the SetTurnPlaced method, so now GamePiece becomes mutable).

GamePiece is used in an ArrayList, I call contains and remove methods which both rely on the equals method to be implemented.

My question is this, is it ok or common practice in Java for some members to not affect equals and hashcode? How will this affect its use in my ArrayList? What type of java Collections would it NOT be safe to use this object now that it is mutable? I've been told that you're not supposed to override equals on mutable objects because it causes some collections to behave "strangely" (I read that somewhere in the java documentation).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

两相知 2024-08-31 16:09:52

是的,当然,您如何定义 equalshashCode,以及如何/何时改变对象,可能会导致集合表现“奇怪”。下面是一个示例:

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 根据设置的位定义了 equalshashCodeHashSet 使用 hashCodeequals 查找对象。通过修改 bitset,它现在具有不同的 hashCode,因此 bitsetcol 无法再找到它。

您会注意到,如果 bitsetcol = new ArrayList();,那么它仍然可以找到它!不同的Collection实现对这种变异机制有不同程度的容忍度。


至于你可以在可变类型上使用 @Override equals 吗?是的,这当然没问题。 BitSet 确实做到了这一点。最重要的是,这正是您所期望的 BitSet 行为(出于性能原因,它被设计为可变的)。

如果您的可变类对 @Override equalshashCode 有意义,那么就这样做。

Yes, certainly how you define your equals and hashCode, and how/when you mutate objects, can cause collections to behave "strangely". Here's an example:

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!!!

What happens here is that Bitset defines equals and hashCode in terms of which bits are set. HashSet finds objects using hashCode and equals. By modifying bitset, it now has a different hashCode, and therefore bitsetcol could no longer find it.

You'll notice that if bitsetcol = new ArrayList<BitSet>();, then it could still find it! Different Collection implementations have different levels of tolerance to this kind of mutation mechanism.


As for can you @Override equals on a mutable type, yes, that is certainly fine. BitSet certainly does that. Most importantly, that's exactly the behavior that you'd expect from a BitSet (which is designed to be mutable for performance reason).

If it makes sense for your mutable class to @Override equals and hashCode, then do so.

伪装你 2024-08-31 16:09:52

注意:这个答案是关于一般的可变对象,即 hashCode 和 equals 方法依赖于可变成员的值的对象。在您的情况下,GamePiece 是可变的,但 equals 和 hashCode 方法不受可变成员的影响。

我的问题是这样,可以吗?
Java 中的常见做法
成员不影响平等和
哈希码?

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

这将如何影响它在我的 ArrayList 中的使用?

一般来说,可变对象不会影响您对 ArrayList 的使用:您可以插入可变对象,add(object),使用其索引访问可变对象,get(index) ,并使用其索引删除可变对象,remove(index),没有任何副作用,因为 ArrayList 不会为这些方法调用 equals()。

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

什么类型的java集合
现在使用这个对象不安全
它是可变的?

只需检查 Collections API 了解什么类或方法受可变对象的影响。一般来说,你不应该使用可变对象作为Map key,但是因为GamePiece的hashCode和equals方法不受可变成员的影响,所以你可以使用它作为key。

“注意:如果将可变对象用作映射键,则必须格外小心。如果对象的值以影响等于比较的方式更改,而该对象是映射中的键,则不会指定映射的行为此禁止的一个特殊情况是不允许映射将自身包含为键,而允许映射将自身包含为值,但建议格外小心:equals 和 hashCode 方法是。在这样的地图上不再有明确的定义。”

Note: this answer is about mutable objects in general, i.e., objects for which the hashCode and equals methods depend on the valus of mutable members. In your case, GamePiece is mutable, but the equals and hashCode methods are not affected by mutable members.

My question is this, is it ok or
common practice in Java for some
members to not affect equals and
hashcode?

This is an acceptable practice, as long as the same members are used to compute equals and hashcode.

How will this affect its use in my ArrayList?

In general, mutable objects won't affect your use of ArrayList: you can insert mutable objects, add(object), access mutable objects using their index, get(index), and delete mutable objects using their index, remove(index), without any side effect because ArrayList does not call equals() for these methods.

If you remove or search for an object using the remove(object) and indexOf(object) methods, ArrayList will call equals() on the objects in the ArrayList, so your program needs to be aware that the objects in the ArrayList might have changed since they were inserted. This won't be a problem with GamePiece as the equals() method is not dependent on the mutable member.

What type of java Collections would it
NOT be safe to use this object now
that it is mutable?

Just check the Collections API to learn what classes or methods are affected by mutable objects. In general, you should not use mutable objects as Map key, but because the hashCode and equals methods of GamePiece are not affected by the mutable member, you can use it as a key.

"Note: great care must be exercised if mutable objects are used as map keys. The behavior of a map is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is a key in the map. A special case of this prohibition is that it is not permissible for a map to contain itself as a key. While it is permissible for a map to contain itself as a value, extreme caution is advised: the equals and hashCode methods are no longer well defined on such a map."

那一片橙海, 2024-08-31 16:09:52

其优点之一是您可以根据对象的需要自由设计 .equals().hashcode()

某些类型的集合非常依赖 .equals().hashcode() 的行为非常一致本文介绍如何使用最佳实践覆盖这些方法

Part of the beauty is that you're able to freely design your .equals() and .hashcode() as your object necessitates.

Certain types of collections are very dependent on .equals() and .hashcode() behaving very consistently. This article explains how to override these methods using best practices.

流云如水 2024-08-31 16:09:52

平等具有您想要赋予它的含义。

在您的情况下,您明确表示具有不同 m_nTurnPlacedGamePiece 实例将被视为相同的对象。因此,m_nTurnPlaced 是该对象的一种状态,不应在 equals(o)hashcode() 上考虑它。

这是什么意思?

  • 首先,当您更改 m_nTurnPlaced 时,GamePiece 的哈希码不会更改,这很好!否则,您无法使用哈希图或哈希集,
  • 当您在列表上使用添加或删除时,您将正确考虑 GameState:这实际上意味着您无法区分两个 GameState code> 具有不同的 m_nTurnPlaced 值。

Equality has the meaning that you want to give to it..

In your case you explictly mean that instance of GamePiece that have different m_nTurnPlaced will be considered and treated as equal objects. So m_nTurnPlaced is a state of this object and it shouldn't be considered on equals(o) and hashcode().

What does it mean?

  • first of all hashcode of GamePiece won't change when you change m_nTurnPlaced and this is good! Otherwise you couldn't use hashmaps or hashsets,
  • when you'll use add or remove on lists you will comsider the GameState correctly: this actually implies that you can't distinguish two GameStates with different m_nTurnPlaced values..
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文