首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java HashMap containsKey

Java HashMap containsKey
EN

Stack Overflow用户
提问于 2020-07-13 06:57:22
回答 3查看 673关注 0票数 6

我有以下代码

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

public class Person {
  private String name;
  private long birthTime;

  @Override
  public int hashCode() {
    return Objects.hash(name, birthTime);
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (!(obj instanceof Person)) {
      return false;
    }
    Person other = (Person) obj;
    return Objects.equals(name, other.name)
        && birthTime == other.birthTime;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public long getBirthTime() {
    return birthTime;
  }

  public void setBirthTime(long birthTime) {
    this.birthTime = birthTime;
  }

  public static Person person(String name, long time) {
    Person p = new Person();
    p.setName(name);
    p.setBirthTime(time);
    return p;
  }

  public static void main(String[] args) {
    Map<Person, Person> map = new HashMap<>();
    Person p = person("alice", 3);
    System.out.println("1. " + map.containsKey(p));

    map.put(p, p);
    System.out.println("2. " + map.containsKey(p));

    p.setName("charlie");
    System.out.println("3. " + map.containsKey(p));

    Person p2 = person("alice", 3);
    System.out.println("4. " + map.containsKey(p2));

    Person p3 = person("charlie", 3);
    System.out.println("5. " + map.containsKey(p3));
  }
}

我期望输出为假、真、真、假和真。然而,输出是假的,真的,假的。

我正在寻找如何输出是错误的第3和第5种情况。HashMap containsKey的行为是什么?

为什么输出是假的,即使关键对象在地图中。针对Person类,等于和hashcode方法都被重写。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-07-13 07:01:02

以下语句破坏了您的Map:

代码语言:javascript
复制
p.setName("charlie");

它将导致变量p引用的键不再定位在与其hashCode()匹配的bin中,因为您正在更改其hashCode()

如果更改影响到hashCode()equals()的结果,则不应该更改已在Map中的键的状态。

代码语言:javascript
复制
p.setName("charlie");
System.out.println("3. " + map.containsKey(p));

返回false,因为名为"charlie“的Person实例与名为"alice”的Person实例没有映射到同一个bin。因此,containsKey()在与名称"charlie“匹配的bin中搜索p,但在那里找不到它。

代码语言:javascript
复制
Person p2 = person("alice", 3);
System.out.println("4. " + map.containsKey(p2));

返回false,因为p2不等于p (它们有不同的名称)。

代码语言:javascript
复制
Person p3 = person("charlie", 3);
System.out.println("5. " + map.containsKey(p3));

返回false,因为键p位于与"alice“名称匹配的bin中,即使它当前的名称是"charlie",所以containsKey()在错误的bin中搜索它,却找不到它。

票数 5
EN

Stack Overflow用户

发布于 2020-07-13 07:02:46

在将对象作为键添加到HashMap中之后,您将以更改哈希代码的方式修改该对象。这就像给某人你的联系方式,搬家,然后仍然期待他们能够找到你。

当您向映射添加一个键时,它会存储哈希代码。当您试图查找密钥时,映射将询问要查找的密钥的哈希代码,并有效地查找具有相同存储的哈希代码的任何条目。由于“新”哈希代码与“旧”哈希代码不匹配,因此无法找到任何可以与equals检查的候选哈希代码。

基本上,在将对象用作映射中的键后,不应该修改任何影响哈希代码或相等性的内容。

票数 3
EN

Stack Overflow用户

发布于 2020-07-13 14:12:50

提供更多关于Eran答案的信息。我检查了一些HashMap的来源。

代码语言:javascript
复制
public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
    ...
        tab[i] = newNode(hash, key, value, null);
    ...
}

public boolean containsKey(Object key) {
    return getNode(hash(key), key) != null;
}

在第三种情况下,“节点”中键的哈希值保持不变,即使您将其‘名称’更改为"Charlie“。这就是为什么它返回假的原因。似乎永远不应该更改对象键,因为它会破坏哈希(键)不匹配的映射。

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

https://stackoverflow.com/questions/62870691

复制
相关文章

相似问题

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