首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Java HashMap containsKey返回现有对象的false

Java HashMap containsKey返回现有对象的false
EN

Stack Overflow用户
提问于 2014-02-06 10:33:48
回答 4查看 52.2K关注 0票数 39

我有一个用于存储对象的HashMap:

代码语言:javascript
运行
复制
    private Map<T, U> fields = Collections.synchronizedMap(new HashMap<T, U>());

但是,当试图检查键是否存在时,containsKey方法返回false

实现了equalshashCode方法,但没有找到关键。

调试一段代码时:

代码语言:javascript
运行
复制
    return fields.containsKey(bean) && fields.get(bean).isChecked();

我有:

代码语言:javascript
运行
复制
   bean.hashCode() = 1979946475 
   fields.keySet().iterator().next().hashCode() = 1979946475    
   bean.equals(fields.keySet().iterator().next())= true 
   fields.keySet().iterator().next().equals(bean) = true

代码语言:javascript
运行
复制
fields.containsKey(bean) = false

是什么导致了这种奇怪的行为?

代码语言:javascript
运行
复制
public class Address extends DtoImpl<Long, Long> implements Serializable{

   <fields>
   <getters and setters>

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + StringUtils.trimToEmpty(street).hashCode();
    result = prime * result + StringUtils.trimToEmpty(town).hashCode();
    result = prime * result + StringUtils.trimToEmpty(code).hashCode();
    result = prime * result + ((country == null) ? 0 : country.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Address other = (Address) obj;
    if (!StringUtils.trimToEmpty(street).equals(StringUtils.trimToEmpty(other.getStreet())))
        return false;
    if (!StringUtils.trimToEmpty(town).equals(StringUtils.trimToEmpty(other.getTown())))
        return false;
    if (!StringUtils.trimToEmpty(code).equals(StringUtils.trimToEmpty(other.getCode())))
        return false;
    if (country == null) {
        if (other.country != null)
            return false;
    } else if (!country.equals(other.country))
        return false;
    return true;
}


}
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-02-06 11:01:20

在将键插入地图后,您不应修改它。

编辑:我在地图中找到了javadoc的摘录:

注意:如果将可变对象用作映射键,则必须非常小心。如果对象的值以影响等于比较的方式更改,而对象是映射中的键,则不指定映射的行为。

示例中有一个简单的包装类:

代码语言:javascript
运行
复制
public static class MyWrapper {

  private int i;

  public MyWrapper(int i) {
    this.i = i;
  }

  public void setI(int i) {
    this.i = i;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    return i == ((MyWrapper) o).i;
  }

  @Override
  public int hashCode() {
    return i;
  }
}

而测试:

代码语言:javascript
运行
复制
public static void main(String[] args) throws Exception {
  Map<MyWrapper, String> map = new HashMap<MyWrapper, String>();
  MyWrapper wrapper = new MyWrapper(1);
  map.put(wrapper, "hello");
  System.out.println(map.containsKey(wrapper));
  wrapper.setI(2);
  System.out.println(map.containsKey(wrapper));
}

产出:

代码语言:javascript
运行
复制
true
false

注意:如果您不覆盖hashcode(),那么只会得到true

票数 31
EN

Stack Overflow用户

发布于 2014-02-06 11:06:18

正如阿诺德·德诺埃尔所指出的那样,修改密钥可以产生这种效果。原因是containsKey关心散列图中密钥的桶,而迭代器不关心。如果映射中的第一个键--不考虑桶--恰好是你想要的那个,那么你就可以得到你看到的行为。如果地图中只有一个条目,这当然是有保证的。

想象一张简单的两桶地图:

代码语言:javascript
运行
复制
[0: empty]  [1: yourKeyValue]

迭代器如下所示:

  • 迭代桶0中的所有元素:没有
  • 迭代桶1中的所有元素:只有一个yourKeyValue

然而,containsKey方法如下所示:

  • keyToFind有一个hashCode() == 0,所以让我看看桶0(只在那里)。哦,它是空的-返回false.

事实上,即使钥匙留在同一个桶里,你也会遇到这个问题!如果您查看HashMap的实现,您将看到每个键值对都与密钥的哈希代码一起存储。当映射想要检查存储的密钥和传入的密钥时,它使用equals

代码语言:javascript
运行
复制
((k = e.key) == key || (key != null && key.equals(k))))

这是一个很好的优化,因为这意味着具有不同hashCodes的键碰巧碰撞到同一个桶中,这将被看作是非常便宜的不相等的(只是int比较)。但这也意味着更改密钥--这不会改变存储的e.key字段--将破坏映射。

票数 12
EN

Stack Overflow用户

发布于 2014-06-03 22:15:48

调试java源代码时,我意识到containsKey方法针对键集中的每个元素检查搜索密钥上的两件事:、hashCode、等于;它按照这个顺序进行检查。

这意味着,如果是obj1.hashCode() != obj2.hashCode(),则返回false (而不计算obj1.equals(obj2) )。但是,如果是obj1.hashCode() == obj2.hashCode(),则返回obj1.equals(obj2)

您必须确保这两种方法都是-may,您必须重写它们--对于您定义的标准,计算值为true。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21600344

复制
相关文章

相似问题

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