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()
    ,直到它没有匹配项或找到相等的对象为止
3) equals(Object o)方法将传递的对象(即对象o)与驻留在具有给定哈希代码的bucket中的所有对象进行比较。那为什么它在很早就发现了一个的时候还不停止通信呢。例如,在bucket 1928中,car1 car4 car5驻留,因此当car6调用get()调用equals()时,如果car6与car1进行比较并发现相等,则应停止比较,但相反,它会比较3次。为什么?


您假设它首先与
car1
进行比较。散列映射实际上是无序的——无法保证将比较具有相同散列码的候选顺序。但当找到匹配项时,它将停止。如果更改哈希代码使其更合理,则很可能只需要检查一项。

为什么不查看源代码?仅当引用不相同时才会调用equals。i、 e.它首先执行
=
。@PeterLawrey调用get()时调用hashcode,然后调用equals。所以当==比较发生时,@Nizam在hashCode之后,在equals之前。如果引用相同,则不需要相等。请简要说明我的第3点,因为每当我运行get(car6)程序时,对象car6都会得到相同的结果,即相等调用三次。在比较任何其他对象之前,是否存在car6比较car1并返回true的可能性。因此,只能调用1次。@Nizam:当前,您的
hashCode()
方法在所有情况下都返回1。这使得它是一个非常糟糕的哈希代码。如果您返回
model.hashCode()
,则它将只查找具有相同哈希代码的车型。(这并不一定意味着他们是平等的,但很有可能。)在将来,如果你不在问题后面添加额外的位,这将是有用的。。。