Java HashMap containsKey
Java HashMap containsKey
我有以下代码
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));
}
}
我期望输出为假、真、真、假和真。
但是,输出是false,true,false,false,false.
我正在寻找第 3 和第 5 种情况的输出如何为假。 HashMap containsKey 的行为是什么?
为什么即使 Key 对象存在于 Map 中,输出仍为 false。 Person class.
的 equals 和 hashcode 方法都被覆盖了
以下语句破坏了您的地图:
p.setName("charlie");
它导致变量 p
引用的键不再位于与其 hashCode()
匹配的容器中,因为您正在更改其 hashCode()
.
如果更改影响 hashCode()
或 equals()
.
的结果,则永远不要更改已在 Map 中的键的状态
p.setName("charlie");
System.out.println("3. " + map.containsKey(p));
Returns false
因为名称为“charlie”的 Person
实例未映射到与名称为“alice”的 Person
实例相同的 bin .因此 containsKey()
在与名称“charlie”匹配的容器中搜索 p
,但没有找到它。
Person p2 = person("alice", 3);
System.out.println("4. " + map.containsKey(p2));
Returns false
因为 p2
不等于 p
(他们有不同的名字)。
Person p3 = person("charlie", 3);
System.out.println("5. " + map.containsKey(p3));
Returns false
由于密钥 p
位于与名称“alice”匹配的 bin 中,即使它的当前名称是“charlie”,所以 containsKey()
在错误的 bin 中搜索它,但没有找到它。
您在将对象添加为 HashMap
中的键后对其进行修改,更改散列码的方式。这就像给别人你的联系方式,搬家,然后仍然希望他们能够找到你。
当您向地图添加键时,它会存储哈希码。当您尝试 查找 键时,地图会询问您要查找的键的散列码,并有效地找到具有相同存储散列码的任何条目。由于“新”散列码与“旧”散列码不匹配,因此无法找到任何候选人来检查equals
。
基本上,在将对象用作映射中的键后,您不应修改任何影响哈希码或相等性的内容。
添加更多关于 Eran answer 的信息。我查看了一些HashMap的来源。
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;
}
在第 3 种情况下,即使您将其名称更改为“查理”,“节点”中键的哈希值也保持不变。这就是它 return 错误的原因。似乎你永远不应该更改对象键,因为它会因 hash(key)
的不匹配而破坏映射
我有以下代码
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));
}
}
我期望输出为假、真、真、假和真。 但是,输出是false,true,false,false,false.
我正在寻找第 3 和第 5 种情况的输出如何为假。 HashMap containsKey 的行为是什么?
为什么即使 Key 对象存在于 Map 中,输出仍为 false。 Person class.
的 equals 和 hashcode 方法都被覆盖了以下语句破坏了您的地图:
p.setName("charlie");
它导致变量 p
引用的键不再位于与其 hashCode()
匹配的容器中,因为您正在更改其 hashCode()
.
如果更改影响 hashCode()
或 equals()
.
p.setName("charlie");
System.out.println("3. " + map.containsKey(p));
Returns false
因为名称为“charlie”的 Person
实例未映射到与名称为“alice”的 Person
实例相同的 bin .因此 containsKey()
在与名称“charlie”匹配的容器中搜索 p
,但没有找到它。
Person p2 = person("alice", 3);
System.out.println("4. " + map.containsKey(p2));
Returns false
因为 p2
不等于 p
(他们有不同的名字)。
Person p3 = person("charlie", 3);
System.out.println("5. " + map.containsKey(p3));
Returns false
由于密钥 p
位于与名称“alice”匹配的 bin 中,即使它的当前名称是“charlie”,所以 containsKey()
在错误的 bin 中搜索它,但没有找到它。
您在将对象添加为 HashMap
中的键后对其进行修改,更改散列码的方式。这就像给别人你的联系方式,搬家,然后仍然希望他们能够找到你。
当您向地图添加键时,它会存储哈希码。当您尝试 查找 键时,地图会询问您要查找的键的散列码,并有效地找到具有相同存储散列码的任何条目。由于“新”散列码与“旧”散列码不匹配,因此无法找到任何候选人来检查equals
。
基本上,在将对象用作映射中的键后,您不应修改任何影响哈希码或相等性的内容。
添加更多关于 Eran answer 的信息。我查看了一些HashMap的来源。
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;
}
在第 3 种情况下,即使您将其名称更改为“查理”,“节点”中键的哈希值也保持不变。这就是它 return 错误的原因。似乎你永远不应该更改对象键,因为它会因 hash(key)
的不匹配而破坏映射