首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >为什么我在Java HashMap中得到了重复的键?

为什么我在Java HashMap中得到了重复的键?
EN

Stack Overflow用户
提问于 2016-07-15 13:53:59
回答 5查看 2.6K关注 0票数 19

我似乎在标准的Java HashMap中得到了重复的键。所谓“复制”,我的意思是键通过它们的equals()方法是相等的。下面是有问题的代码:

代码语言:javascript
复制
import java.util.Map;
import java.util.HashMap;

public class User {
    private String userId;
    public User(String userId) { 
        this.userId = userId;
    }
    public boolean equals(User other) {
        return userId.equals(other.getUserId());
    }
    public int hashCode() {
        return userId.hashCode();
    }
    public String toString() {
        return userId;
    }

    public static void main(String[] args) {
        User arvo1 = new User("Arvo-Part");
        User arvo2 = new User("Arvo-Part");
        Map<User,Integer> map = new HashMap<User,Integer>();
        map.put(arvo1,1);
        map.put(arvo2,2);

        System.out.println("arvo1.equals(arvo2): " + arvo1.equals(arvo2));
        System.out.println("map: " + map.toString());
        System.out.println("arvo1 hash: " + arvo1.hashCode());
        System.out.println("arvo2 hash: " + arvo2.hashCode());
        System.out.println("map.get(arvo1): " + map.get(arvo1));
        System.out.println("map.get(arvo2): " + map.get(arvo2));
        System.out.println("map.get(arvo2): " + map.get(arvo2));
        System.out.println("map.get(arvo1): " + map.get(arvo1));
    }
}

下面是结果输出:

代码语言:javascript
复制
arvo1.equals(arvo2): true
map: {Arvo-Part=1, Arvo-Part=2}
arvo1 hash: 164585782
arvo2 hash: 164585782
map.get(arvo1): 1
map.get(arvo2): 2
map.get(arvo2): 2
map.get(arvo1): 1

如您所见,两个User对象上的equals()方法返回true,它们的散列代码相同,但它们各自在map中形成一个不同的key。此外,map在最后四个User调用中继续区分两个get()密钥。

这直接与documentation相矛盾

更正式地说,如果此映射包含从键k到值v的映射,则(key==null?k==null : key.equals(k)),则此方法返回v;否则返回null。(最多只能有一个这样的映射。)

这是一个bug吗?我是不是漏掉了什么?我运行的是Java版本的1.8.0_92,它是我通过Homebrew安装的。

编辑:此问题已被标记为此other question的副本,但我将保留此问题不变,因为它确定了与equals()似乎不一致,而另一个问题假定错误出在hashCode()上。希望这个问题的存在将使这个问题更容易搜索。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2016-07-15 14:08:23

问题出在您的equals()方法中。Object.equals()的签名是equals(OBJECT),但在本例中它是equals(USER),所以这是两个完全不同的方法,并且散列映射调用的是带有Object参数的方法。您可以通过将@Override注释放在您的equals上来验证这一点-它将生成一个编译器错误。

equals方法应该是:

代码语言:javascript
复制
  @Override
  public boolean equals(Object other) {
    if(other instanceof User){
        User user = (User) other;
        return userId.equals(user.userId);
    }

    return false;
}

作为最佳实践,您应该始终将@Override放在您所覆盖的方法上-它可以为您省去很多麻烦。

票数 28
EN

Stack Overflow用户

发布于 2016-07-15 14:08:12

您的equals方法不会重写equals,而且Map中的类型会在运行时被擦除,因此实际调用的equals方法是equals(Object)。你的等号应该看起来更像这样:

代码语言:javascript
复制
@Override
public boolean equals(Object other) {
    if (!(other instanceof User))
        return false;
    User u = (User)other;
    return userId.equals(u.userId);
}
票数 13
EN

Stack Overflow用户

发布于 2016-07-15 14:12:49

好的,首先,代码不能编译。缺少此方法:

代码语言:javascript
复制
other.getUserId()

但是除此之外,你还需要@Override equals方法,像Eclipse这样的集成开发环境也可以帮助生成equalshashCode btw。

代码语言:javascript
复制
@Override
public boolean equals(Object obj)
{
  if(this == obj)
     return true;
  if(obj == null)
     return false;
  if(getClass() != obj.getClass())
     return false;
  User other = (User) obj;
  if(userId == null)
  {
     if(other.userId != null)
        return false;
  }
  else if(!userId.equals(other.userId))
     return false;
  return true;
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38388751

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档