Hashing Equals仅返回true

时间:2014-12-02 08:53:57

标签: collections map hashmap equals hashcode

考虑示例代码:

class EmployeeClass {
    int id;
    public EmployeeClass(int eid) {
        this.id=eid;
    }

    @Override
    public int hashCode(){
        return this.id;
    }
    @Override
    public boolean equals(Object o){
        return true;
    }
}

public class HashcodeAndEquals {

    public static void main(String[] args) {
        Map map=new HashMap();
        EmployeeClass e1=new EmployeeClass(1);
        map.put(e1, "Employee 1");                // line 1
        EmployeeClass e2=new EmployeeClass(2);
        map.put(e2, "Employee 2");
        EmployeeClass e3=new EmployeeClass(3);
        EmployeeClass e4=new EmployeeClass(1);   // line 2
        EmployeeClass e5=new EmployeeClass(1);
        map.put(e5, "Employee 5");                // line 3
        System.out.println("e1 -> "+map.get(e1)); 
        System.out.println("e2 -> "+map.get(e2));
        System.out.println("e3 -> "+map.get(e3));
        System.out.println("e4 -> "+map.get(e4)); // line 4
        System.out.println("e5 -> "+map.get(e5));
    }
}

输出:

e1 -> Employee 5
e2 -> Employee 2
e3 -> null
e4 -> Employee 5

e5 -> Employee 5

第1行运行后,第3行覆盖e1的值,但我的equals方法仅返回true。同样在第4行,我们得到e4的值,即使equals方法只返回true。由于equals方法没有比较只返回true,因此put和get的工作原理如何。幕后发生了什么?

1 个答案:

答案 0 :(得分:0)

我猜你是否感到惊讶,并非所有人都是员工5?等于总是返回true,所以e5应该覆盖所有这些,对吧?

HashMap使用"存储桶"在幕后。让我们说只有2,简单来说就是这样。一个真正的HashMap还有更多。

当您将对象放入HashMap时,它首先查看hashCode。 (这就是为什么它被称为HashMap。)基于hashCode,它选择一个存储桶来存储它。对于e1,hashCode是1,所以它会选择存储桶1。对于e2,它是2,因此进入存储桶2. e3的hashCode为3,但只有2个存储桶,所以它将进入存储桶3模数2,即{1} e4因同一原因进入存储桶2,e5又返回1。

请注意,我极其简化;实际上这个过程有点复杂,但这应该足以解释事情。

所以我们有以下桶:

bucket 1 | bucket 2
e5       | e4
e3       | e2
e1       |

现在是时候检索价值了。当我检索e1时,hashCode仍为1,因此它在存储桶1中查找。在那里,它选择equals e1的第一个对象,即e5:你输入的最后一个对象,显然是第一个出来的对象。 e2指向存储区2,因此在此示例中,您将得到e4

在您的情况下,您实际上从未将e3e4放入HashMap。但由于e3的hashCode指向存储桶1,并且它等于e5,因此当您查找e3时,您仍然可以获得e5虽然它实际上并不存在。

正如我所说,这是对事物的极端简化。在真正的HashMap中,有超过2个桶。因此,在您的情况下,e3有一个指向空桶的哈希码,而e1e4e5的hashCodes显然都指向同一个存储桶。< / p>

这就是为什么在编写hashCode时给它一个好的&#34;分发&#34;重要的原因。如果你总是返回42,那么所有对象总是会进入同一个桶,这会把你的HashMap变成一个非常笨拙的ArrayList。您将失去HashMap为您提供的性能优势。