简体   繁体   中英

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 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's internal hash Method defends against poor quality hash functions.

To test these contracts, I have written a bean class with incorrect but legal implementations of the equals and hashCode method.

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,

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 .

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.

HashMap has a little trick where it compares object references before using equals . Since you're using the same object references for adding the elements and for retrieving them, HashMap will return them correctly.

See Java 7 source here (Java 8 did a pretty big revamp of HashMap but it does something similar)

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:

1) Index of table cell in which (Key,Value) will save calculates as key.hashCode();

2) Keys in HashMap compare by equals() or by reference comparing.

So, in your situation all pairs of (K,V) will store in one cell of HashMap table as LinkedList. And you can get them from Map because references for keys will equals

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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