简体   繁体   English

HashMap具有错误的equals和HashCode实现

[英]HashMap with incorrect equals and HashCode implementation

According to what I have read, 根据我的读物,

to use an object as the key to a hashMap, it has to provide a correct override and implementation of the equals and hashCode method. 要使用对象作为hashMap的键,它必须提供对equalshashCode方法的正确覆盖和实现。 HashMap get(Key k) method calls hashCode method on the key object and applies returned hashValue to its own static hash function to find a bucket location(backing array) where keys and values are stored in form of a nested class called Entry (Map.Entry). HashMap的get(Key k)方法调用键对象上的hashCode方法,并将返回的hashValue应用于其自己的静态哈希函数,以查找存储区位置(支持数组),在该存储区中,键和值以称为Entry(Map)的嵌套类的形式存储。条目)。 HashMap's internal hash Method defends against poor quality hash functions. HashMap的内部哈希方法可以防御质量差的哈希函数。

To test these contracts, I have written a bean class with incorrect but legal implementations of the equals and hashCode method. 为了测试这些合同,我编写了一个bean类,其中带有equalshashCode方法的错误但合法的实现。

The class: 班级:

public class HashVO {

    private String studentName;
    private int age;
    private boolean isAdult;

    public HashVO(String studentName, int age, boolean isAdult) {
        super();
        this.studentName = studentName;
        this.age = age;
        this.isAdult = isAdult;
    }
    public String getStudentName() {
        return studentName;
    }
    public void setStudentName(String studentName) {
        this.studentName = studentName;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public boolean isAdult() {
        return isAdult;
    }
    public void setAdult(boolean isAdult) {
        this.isAdult = isAdult;
    }
    @Override
    public String toString() {
        return studentName + " : " + age + " : " + isAdult;
    }
    @Override
    public boolean equals(Object obj) {
        return false;
    }
    @Override
    public int hashCode() {
        return 31;
    }

}

In this case, the hash method of the HashMap, 在这种情况下,HashMap的hash方法

static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

should also return same value everytime because the hashcode always returns 31. So if objects of class HashVO are used as key of a hashMap, the get method should not work, as it should go to the same bucket to retrieve the objects and the equals method always returns false so it will not be able to able to find a match for the key object . 每次也应返回相同的值,因为哈希码始终返回31。因此,如果将HashVO类的对象用作hashMap的键, 则get方法将不起作用,因为它应转到同一存储桶以检索对象和equals方法总是返回false,因此它不能找到匹配的关键对象

But when I am using this method, 但是当我使用这种方法时

public static void main(String[] args) {
        HashMap<HashVO, String> voMap = new HashMap<HashVO, String>();
        HashVO vo = new HashVO("Item1", 25, true);
        HashVO vo1 = new HashVO("Item2", 12, false);
        HashVO vo2 = new HashVO("Item3", 1, false);
        voMap.put(vo, "Item");
        voMap.put(vo1, "Item1");
        voMap.put(vo2, "Item2");
        System.out.println(voMap.get(vo));
        System.out.println(voMap.get(vo1));
        System.out.println(voMap.get(vo2));
    }

the output is correct, and showing 输出正确,并显示

Item
Item1
Item2

I want to understand why this correct output is coming even as the Equals and HashCode method implementation is incorrect. 我想了解为什么即使Equals和HashCode方法实现不正确,也要输出正确的输出。

HashMap has a little trick where it compares object references before using equals . HashMap有一个小技巧,可以在使用equals之前比较对象引用。 Since you're using the same object references for adding the elements and for retrieving them, HashMap will return them correctly. 由于您使用相同的对象引用来添加元素和检索元素,因此HashMap将正确返回它们。

See Java 7 source here (Java 8 did a pretty big revamp of HashMap but it does something similar) 在此处查看Java 7的源代码(Java 8对HashMap进行了相当大的改进,但它做了类似的事情)

final Entry<K,V> getEntry(Object key) {
    if (size == 0) {
        return null;
    }

    int hash = (key == null) ? 0 : hash(key);
    for (Entry<K,V> e = table[indexFor(hash, table.length)];
         e != null;
         e = e.next) {
        Object k;
        // HERE. Uses == with the key
        if (e.hash == hash &&
            ((k = e.key) == key || (key != null && key.equals(k)))) 
            return e;
    }
    return null;
}

Note that this isn't part of the docs, so don't depend on it. 请注意,这不是文档的一部分,因此请不要依赖它。

The HashMap works like this: HashMap的工作方式如下:

1) Index of table cell in which (Key,Value) will save calculates as key.hashCode(); 1)将要保存(Key,Value)的表单元格的索引计算为key.hashCode();

2) Keys in HashMap compare by equals() or by reference comparing. 2)HashMap中的键通过equals()或通过引用比较进行比较。

So, in your situation all pairs of (K,V) will store in one cell of HashMap table as LinkedList. 因此,在您的情况下,所有(K,V)对都将作为LinkedList存储在HashMap表的一个单元格中。 And you can get them from Map because references for keys will equals 而且您可以从Map中获取它们,因为键的引用将等于

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM