根据我的理解,我认为:
两个对象具有相同的hashcode是完全合法的。 如果两个对象相等(使用equals()方法),则它们具有相同的hashcode。 如果两个对象不相等,那么它们就不能有相同的hashcode
我说的对吗?
如果我没猜错的话,我有以下问题: HashMap在内部使用对象的hashcode。那么,如果两个对象可以具有相同的hashcode,那么HashMap如何跟踪它使用的键呢?
有人能解释一下HashMap内部是如何使用对象的hashcode的吗?
根据我的理解,我认为:
两个对象具有相同的hashcode是完全合法的。 如果两个对象相等(使用equals()方法),则它们具有相同的hashcode。 如果两个对象不相等,那么它们就不能有相同的hashcode
我说的对吗?
如果我没猜错的话,我有以下问题: HashMap在内部使用对象的hashcode。那么,如果两个对象可以具有相同的hashcode,那么HashMap如何跟踪它使用的键呢?
有人能解释一下HashMap内部是如何使用对象的hashcode的吗?
当前回答
记住这里对hashmap结构的解释,也许有人可以解释Baeldung上的以下段落:-
Java有接口Map的几个实现,每个实现都有自己的特殊性。
但是,现有的Java核心Map实现都不允许Map处理单个键的多个值。
正如我们所看到的,如果我们试图为同一个键插入两个值,第二个值将被存储,而第一个值将被删除。
它还将返回(由put(K键,V值)方法的每个正确实现):
Map<String, String> map = new HashMap<>();
assertThat(map.put("key1", "value1")).isEqualTo(null);
assertThat(map.put("key1", "value2")).isEqualTo("value1");
assertThat(map.get("key1")).isEqualTo("value2");
其他回答
hashcode决定要检查hashmap的哪个bucket。如果存储桶中有多个对象,则执行线性搜索以查找存储桶中的哪个项目等于所需的项目(使用equals()方法)。
In other words, if you have a perfect hashcode then hashmap access is constant, you will never have to iterate through a bucket (technically you would also have to have MAX_INT buckets, the Java implementation may share a few hash codes in the same bucket to cut down on space requirements). If you have the worst hashcode (always returns the same number) then your hashmap access becomes linear since you have to search through every item in the map (they're all in the same bucket) to get what you want.
大多数情况下,编写良好的hashcode并不完美,但它足够独特,可以为您提供或多或少的恒定访问。
你的第三个断言是不正确的。
两个不相等的对象拥有相同的哈希码是完全合法的。它被HashMap用作“第一遍过滤器”,以便映射可以快速找到具有指定键的可能条目。然后测试具有相同哈希码的键是否与指定的键相等。
您不会希望要求两个不相等的对象不能具有相同的哈希码,否则将限制为232个可能的对象。(这也意味着不同类型甚至不能使用对象的字段来生成哈希码,因为其他类可以生成相同的哈希码。)
我不会详细介绍HashMap是如何工作的,但是会给出一个例子,这样我们就可以通过将HashMap与现实联系起来来记住它是如何工作的。
我们有Key, Value,HashCode和bucket。
在一段时间内,我们将把它们与以下内容联系起来:
一个社会 HashCode ->社会地址(总是唯一的) 社会中的房子 Key ->房屋地址。
使用Map.get(key):
Stevie想去他的朋友(Josse)的房子,他住在一个VIP社会的别墅里,让它成为javalavers社会。 Josse的地址是他的SSN(每个人都不一样)。 有一个索引,我们可以根据社会安全号找到协会的名字。 这个索引可以被认为是一个找出HashCode的算法。
SSN协会名称 92313(Josse’s) -爪哇 13214—AngularJSLovers 98080—javalover 53808 -生物爱好者
这个SSN(密钥)首先给我们一个HashCode(来自索引表),它只是社会的名字。 现在,多个房子可以在同一个社会中,所以HashCode可以是公共的。 假设,社会对两个房子都是公用的,我们如何识别我们要去哪个房子,是的,通过使用(SSN)密钥,它只是房子的地址
使用Map.put(关键字,值)
这将通过查找HashCode为该值找到一个合适的社会,然后存储该值。
我希望这能有所帮助,而且这是可以修改的。
你在第三点上错了。两个条目可以具有相同的哈希码,但不相等。看一下HashMap的实现。从OpenJdk中获取。你可以看到它检查哈希值是否相等键值是否相等。如果第三点成立,那么检查键值是否相等就没有必要了。哈希码在键之前进行比较,因为前者是更有效的比较。
如果您有兴趣进一步了解这方面的知识,请参阅Wikipedia关于开放寻址冲突解决的文章,我认为这是OpenJdk实现使用的机制。这种机制与另一个答案中提到的“桶”方法略有不同。
import java.util.HashMap;
public class Students {
String name;
int age;
Students(String name, int age ){
this.name = name;
this.age=age;
}
@Override
public int hashCode() {
System.out.println("__hash__");
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
System.out.println("__eq__");
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Students other = (Students) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
public static void main(String[] args) {
Students S1 = new Students("taj",22);
Students S2 = new Students("taj",21);
System.out.println(S1.hashCode());
System.out.println(S2.hashCode());
HashMap<Students,String > HM = new HashMap<Students,String > ();
HM.put(S1, "tajinder");
HM.put(S2, "tajinder");
System.out.println(HM.size());
}
}
Output:
__ hash __
116232
__ hash __
116201
__ hash __
__ hash __
2
因此,在这里我们可以看到,如果对象S1和S2都有不同的内容,那么我们可以非常确定,我们覆盖的Hashcode方法将为两个对象生成不同的Hashcode(116232,11601)。因为有不同的哈希码,所以它甚至不需要调用EQUALS方法。因为不同的Hashcode保证对象中不同的内容。
public static void main(String[] args) {
Students S1 = new Students("taj",21);
Students S2 = new Students("taj",21);
System.out.println(S1.hashCode());
System.out.println(S2.hashCode());
HashMap<Students,String > HM = new HashMap<Students,String > ();
HM.put(S1, "tajinder");
HM.put(S2, "tajinder");
System.out.println(HM.size());
}
}
Now lets change out main method a little bit. Output after this change is
__ hash __
116201
__ hash __
116201
__ hash __
__ hash __
__ eq __
1
We can clearly see that equal method is called. Here is print statement __eq__, since we have same hashcode, then content of objects MAY or MAY not be similar. So program internally calls Equal method to verify this.
Conclusion
If hashcode is different , equal method will not get called.
if hashcode is same, equal method will get called.
Thanks , hope it helps.