为什么自定义对象不等于 HashMap 的键?

发布于 2024-11-12 17:09:46 字数 1860 浏览 5 评论 0原文

我在使用自己的类作为 HashMap 的键时遇到问题

 public class ActorId {
     private final int playerId;
     private final int id;

     ActorId(int playerId, int id) {
         this.playerId = playerId;
         this.id = id;
     }

     public boolean equals(ActorId other) {
         return this.id == other.id && this.playerId == other.playerId;
     }

     public int hashCode() {
         int hash = 1;
         hash = hash * 31 + playerId;
         hash = hash * 31 + id;
         return hash;
     }

     public String toString() {
         return "#" + playerId + "." + id;
     }

     public int getPlayerId() {
         return playerId;
     }
 }

这是一个失败的 JUnit 测试

 import static org.junit.Assert.*;
 import java.util.Map;
 import org.junit.Test;

 public class ActorIdTest {
     @Test
     public final void testAsMapKey() {
         ActorId a = new ActorId(123, 345);
         ActorId b = new ActorId(123, 345);

         assertTrue(a.equals(b));
         assertEquals(a.hashCode(), b.hashCode());

         // Works with strings as keys
         Map<String, String> map1 = new java.util.HashMap<String, String>();

         map1.put(a.toString(), "test");
         assertEquals("test", map1.get(a.toString()));
         assertEquals("test", map1.get(b.toString()));
         assertEquals(1, map1.size()); 

         // But not with ActorIds
         Map<ActorId, String> map2 = new java.util.HashMap<ActorId, String>();

         map2.put(a, "test");
         assertEquals("test", map2.get(a));
         assertEquals("test", map2.get(b)); // FAILS here
         assertEquals(1, map2.size()); 

         map2.put(b, "test2");
         assertEquals(1, map2.size());
         assertEquals("test2", map2.get(a));
         assertEquals("test2", map2.get(b));
     }
 }

I'm having trouble using my own class as a key for a HashMap

 public class ActorId {
     private final int playerId;
     private final int id;

     ActorId(int playerId, int id) {
         this.playerId = playerId;
         this.id = id;
     }

     public boolean equals(ActorId other) {
         return this.id == other.id && this.playerId == other.playerId;
     }

     public int hashCode() {
         int hash = 1;
         hash = hash * 31 + playerId;
         hash = hash * 31 + id;
         return hash;
     }

     public String toString() {
         return "#" + playerId + "." + id;
     }

     public int getPlayerId() {
         return playerId;
     }
 }

Here is a failing JUnit test

 import static org.junit.Assert.*;
 import java.util.Map;
 import org.junit.Test;

 public class ActorIdTest {
     @Test
     public final void testAsMapKey() {
         ActorId a = new ActorId(123, 345);
         ActorId b = new ActorId(123, 345);

         assertTrue(a.equals(b));
         assertEquals(a.hashCode(), b.hashCode());

         // Works with strings as keys
         Map<String, String> map1 = new java.util.HashMap<String, String>();

         map1.put(a.toString(), "test");
         assertEquals("test", map1.get(a.toString()));
         assertEquals("test", map1.get(b.toString()));
         assertEquals(1, map1.size()); 

         // But not with ActorIds
         Map<ActorId, String> map2 = new java.util.HashMap<ActorId, String>();

         map2.put(a, "test");
         assertEquals("test", map2.get(a));
         assertEquals("test", map2.get(b)); // FAILS here
         assertEquals(1, map2.size()); 

         map2.put(b, "test2");
         assertEquals(1, map2.size());
         assertEquals("test2", map2.get(a));
         assertEquals("test2", map2.get(b));
     }
 }

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

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

发布评论

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

评论(4

千纸鹤带着心事 2024-11-19 17:09:46

您需要更改

public boolean equals(ActorId other) {
    ....
}

public boolean equals(Object other) {
    ....
}

每日提示:始终使用@Override注释。

如果您使用了@Override注释,编译器会捕获错误并说:

ActorId 类型的方法 equals(ActorId) 必须重写或实现超类型方法

You need to change

public boolean equals(ActorId other) {
    ....
}

to

public boolean equals(Object other) {
    ....
}

Tip of the day: Always use @Override annotation.

If you had used the @Override annotation, the compiler would have caught the error and said:

The method equals(ActorId) of type ActorId must override or implement a supertype method

追我者格杀勿论 2024-11-19 17:09:46

您的代码是正确的,但您还需要重写从 Object 继承的 equals 方法。

将其添加到您的 ActorId 类中:

@Override
 public boolean equals(Object other) {
    if(other == null || other.getClass() != getClass())
        return false;
    return equals((ActorId)other);
 }

Your code is correct, but you also need to override the equals method inherited from Object.

Add this to your ActorId class:

@Override
 public boolean equals(Object other) {
    if(other == null || other.getClass() != getClass())
        return false;
    return equals((ActorId)other);
 }
痴梦一场 2024-11-19 17:09:46

您绝对必须重写方法 equals(Object),并且对于 Map (HashMap) 的某些实现,还需要重写方法 hashCode()。

我遇到了同样的问题,如果没有自定义 hashCode 实现,则永远不会调用类“ActorId”的 equals 方法。

You definitely must override the method equals(Object), and for certain implementation of a Map (HashMap) it is also necesary that you overrdide the method hashCode().

I had the same problem, and without the custom hashCode implementation the equals method of the class "ActorId" was never called.

南…巷孤猫 2024-11-19 17:09:46

默认情况下,Java 调用 boolean equals(Object obj);
因此,您登录是正确的,但如果您想覆盖 equals() 使用 Object 作为参数,并通过 instanceOfgetClass() 检查类并进行类转换。

if (obj instanceOf ActorId) {
    ActorId other = (ActorId)obj;
    ... compare fields
}

By default Java invokes boolean equals(Object obj);
So, you login is correct but if you want to OVERRIDE equals() use Object as a parameter and and check the class by instanceOf or getClass() and do a class casting.

if (obj instanceOf ActorId) {
    ActorId other = (ActorId)obj;
    ... compare fields
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文