Java 关于散列的小混乱
考虑以下代码:Java 关于散列的小混乱,java,hash,collections,equals,hashcode,Java,Hash,Collections,Equals,Hashcode,考虑以下代码: public class CarEqualsTestAgain { String model; public CarEqualsTestAgain(String x) { this.model=x; } @Override public int hashCode(){ //bad hashcode System.out.println("__hash__"); ret
public class CarEqualsTestAgain {
String model;
public CarEqualsTestAgain(String x) {
this.model=x;
}
@Override
public int hashCode(){ //bad hashcode
System.out.println("__hash__");
return 1;
}
@Override
public boolean equals(Object o){
System.out.println("In equals");
if((o instanceof CarEqualsTestAgain) && ((CarEqualsTestAgain)o).model==this.model){
return true;
}
else
return false;
}
public static void main(String[] args) {
Map map=new HashMap();
CarEqualsTestAgain car1=new CarEqualsTestAgain("8");
map.put(car1, "Red");
System.out.println("Key1 : "+map.get(car1)); //Line 1
CarEqualsTestAgain car2=new CarEqualsTestAgain("8");
System.out.println("Key2 : "+map.get(car2)); //Line 2
CarEqualsTestAgain car3=car1;
System.out.println("Key3 : "+map.get(car3)); //Line 3
CarEqualsTestAgain car4=new CarEqualsTestAgain("9");
map.put(car4, "Red");
System.out.println("Key4 : "+map.get(car4)); //Line 4
CarEqualsTestAgain car5=new CarEqualsTestAgain("10");
map.put(car5, "Red");
System.out.println("Key5 : "+map.get(car5)); //Line 5
CarEqualsTestAgain car6=new CarEqualsTestAgain("8");
map.put(car6, "Green");
System.out.println("Key6 : "+map.get(car6)); //Line 6
key=(String)map.get(car1);
System.out.println("Key1 : "+key); //Line 7
}
}
将输出打印为:
__hash__
__hash__
Key1 : Red
__hash__
In equals
Key2 : Red
__hash__
Key3 : Red
__hash__
In equals
__hash__
Key4 : Red
__hash__
In equals
In equals
__hash__
Key5 : Red
__hash__
In equals
In equals
In equals
__hash__
In equals
In equals
In equals
Key6 : Red
__hash__
In equals
In equals
Key1 : Green
我的问题是:
1) 当创建每个对象时,JVM计算其hashcode并将其放入bucket中,或者当调用Hashmap put()方法时,那么只有JVM使用键对象来计算hashcode
2) put()和get()同时调用hashcode和equals方法。因此,put()方法根据bucket中的对象数量正确地调用重写的equals(),如第1,4,5,6行的输出所示。但是对于get()方法,它是不同的。对于第1行get()未调用equal(),第2行未调用,第3、4、5行未调用,第6行未调用。第七行没有,为什么
3) equals(Object o)方法将传递的对象(即对象o)与驻留在具有给定哈希代码的bucket中的所有对象进行比较。那为什么它在很早就发现了一个的时候还不停止通信呢。例如,在bucket 1928中,car1 car4 car5驻留,因此当car6调用get()调用equals()时,如果car6与car1进行比较并发现相等,则应停止比较,但相反,它会比较3次。为什么?
当创建每个对象时,JVM计算其hashcode并将其放入bucket中,或者当调用Hashmap put()方法时,那么只有JVM使用键对象来计算hashcode
它只在需要时调用hashCode()
——在本例中,当您调用put()
或get()
时
对于第1行get()未调用equal(),第2行未调用,第3、4、5行未调用,第6行未调用。第七行没有,为什么
你被自己的诊断弄糊涂了。此电话:
System.out.println("Key1 : "+map.get(car1));
相当于:
Object tmp = map.get(car1);
System.out.println("Key1 : " + tmp);
因此,对equals
的调用发生在打印Key1
之前。为了更容易理解,您应该将诊断更改为:
System.out.println("Test 1");
CarEqualsTestAgain car1 = new CarEqualsTestAgain("8");
System.out.println("Created car");
map.put(car1, "Red");
System.out.println("Added car to map");
Object tmp = map.get(car1);
System.out.println("Result of get: " + tmp);
这样就更清楚地知道什么时候发生。通常,put()
和get()
都需要:
- 对要添加/获取的键调用
hashCode()
- 如果该散列码与映射中现有的散列码匹配,则为每个匹配调用
,直到它没有匹配项或找到相等的对象为止equals()
您假设它首先与
car1
进行比较。散列映射实际上是无序的——无法保证将比较具有相同散列码的候选顺序。但当找到匹配项时,它将停止。如果更改哈希代码使其更合理,则很可能只需要检查一项。为什么不查看源代码?仅当引用不相同时才会调用equals。i、 e.它首先执行=
。@PeterLawrey调用get()时调用hashcode,然后调用equals。所以当==比较发生时,@Nizam在hashCode之后,在equals之前。如果引用相同,则不需要相等。请简要说明我的第3点,因为每当我运行get(car6)程序时,对象car6都会得到相同的结果,即相等调用三次。在比较任何其他对象之前,是否存在car6比较car1并返回true的可能性。因此,只能调用1次。@Nizam:当前,您的hashCode()
方法在所有情况下都返回1。这使得它是一个非常糟糕的哈希代码。如果您返回model.hashCode()
,则它将只查找具有相同哈希代码的车型。(这并不一定意味着他们是平等的,但很有可能。)在将来,如果你不在问题后面添加额外的位,这将是有用的。。。