Java 虽然散列值不同,但为什么我的对象存储在同一位置?
我有一个Java 虽然散列值不同,但为什么我的对象存储在同一位置?,java,hashmap,hashcode,Java,Hashmap,Hashcode,我有一个Movie类和我只覆盖hashCode()方法。请在下面找到java类 public class Movie { private String actor; private String name; private String releaseYr; public String getActor() { return actor; } public void setActor(String actor) { this.actor = actor; } public
Movie
类和我只覆盖hashCode()
方法。请在下面找到java类
public class Movie {
private String actor;
private String name;
private String releaseYr;
public String getActor() {
return actor;
}
public void setActor(String actor) {
this.actor = actor;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getReleaseYr() {
return releaseYr;
}
public void setReleaseYr(String releaseYr) {
this.releaseYr = releaseYr;
}
@Override
public int hashCode() {
return actor.hashCode() + name.hashCode() + releaseYr.hashCode();
}
}
我创建了两个Movie
对象,这两个对象的所有属性值都相同,并将它们放在HashMap
中。下面是代码
import java.util.HashMap;
public class Test {
public static void main(String[] args) {
Movie m1 = new Movie();
m1.setActor("Akshay");
m1.setName("Taskvir");
m1.setReleaseYr("2010");
Movie m2 = new Movie();
m2.setActor("Akshay");
m2.setName("Taskvir");
m2.setReleaseYr("2010");
HashMap<Movie, String> map = new HashMap<Movie, String>();
map.put(m1, "Value of m1");
map.put(m2, "Value of m2");
}
}
调试模式下的输出
如果我不重写equals和hashCode方法,那么我也会得到同样的意外结果
根据我的理解,如果我不重写equals
和hashCode
方法,或者只重写equals
方法,那么m1
和m2
对象应该存储在不同的位置,因为m1
和m2
对象的哈希值不同。但在这种情况下,它不会发生
有人能解释一下为什么用不同的散列值,我的对象存储在同一个位置吗
我使用过Java 8。哈希代码的范围非常大,从
Integer.MIN\u值
到Integer.MAX\u值
,而HashMap
通常具有更少的存储桶(默认情况下,新实例化的HashMap
,至少在OpenJDK 11中是16个)。因此,散列代码完全有可能发生冲突,多个对象将被添加到同一个bucket中,这甚至是意料之中的。但是,请注意,如果您没有重写hashCode()
,则此行为完全是偶然的,不能依赖。无论哈希代码是如何计算的,通过您的方法还是默认情况下从对象
类,不同的对象都可以映射到相同的hashmap bucket(数组索引)。散列码除以数组大小,余数给出桶号
Object.hashCode()
(31622540和27844196)生成的两个哈希代码在除以16(初始哈希映射数组大小)时恰好生成相同的余数4
因此,有40亿个不同的哈希代码可用,其中一些必须在同一个桶中结束,因为为每个哈希映射分配40亿个元素的数组将是一种内存浪费
要使哈希映射按预期工作,重要的是相等的对象提供相同的哈希代码
如果只重写equals()
方法,则对象.hashCode()
无法满足该要求,您还必须重写hashCode()
——否则get()
方法将找不到存储在映射中的对象
如果希望两部电影的字段相等,则应提供适当的hashCode()
方法
让我们看看可能的覆盖组合
不凌驾
这两部电影都是不同的,结果是不同的散列映射条目,可能在相同的,可能在不同的存储桶中
仅重写hashCode()
这两部电影是不同的,在同一个bucket中以不同的哈希映射条目结束。如果仍然使用对象
平等定义,那么发明自己的hashCode()
实现是毫无意义的
重写hashCode()和equals()
这两部电影都是相同的,最终只有一个散列映射条目,后面存储的值获胜。发生这种情况的原因是,第二个put()
在哈希代码的bucket下找到一个具有相等键的条目,并简单地替换其值部分
仅覆盖等于()
大错特错!这两部电影都是相同的,但这并没有反映在hashCode()
计算中,因此搜索现有值是否查找到正确的bucket只是运气的问题
@Override
public boolean equals(Object obj) {
Movie m1 = (Movie) obj;
boolean result = false;
if (m1.getActor().equals(this.actor) && m1.getName().equals(this.name)
&& m1.getReleaseYr().equals(this.releaseYr)) {
result = true;
}
return result;
}