In depth understanding of hashcode(), hash(), hash value and overriding equals() and hashCode()Demo

Keywords: Attribute

Recently, I took the time to summarize the basic knowledge of HashMap and sort out the previous questions.

After reading this article, you will learn the following questions

1. What is hash()? What is the role?

2. What is hashcode()? What is the role?

3. What is the hash value?

---------------------------------------------------------------------------------------------------------------------------

1. What is hash()? What is the role?

Old rules, first source code

int hash = hash(key);//Call hash method on key in put method

final int hash(Object k) {
        int h = hashSeed;
        if (0 != h && k instanceof String) {
            return sun.misc.Hashing.stringHash32((String) k);
        }

        h ^= k.hashCode();

        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }

hash() big name hash function (also known as hash function) is a kind of algorithm that transforms the input of any length into the output of fixed length through hash algorithm, and obtains a hash value through a series of calculations (the first attribute value of the Entry node, which will be used later). The hash function features are:

  • If h(k1) ≠ h(k2), then k1 ≠ k2, that is, the hash value is different, then the input value is different from the pre mapping.
  • If k1 ≠ k2, h(k1)=h(k2), the collision will occur.
  • If h(k1)=h(k2), k1 is not necessarily equal to k2;

2. What is hashcode()?

//hashCode() in hashMap
public final int hashCode() {
            return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue());
        }

//hashCode() in Objects
public static int hashCode(Object o) {
        return o != null ? o.hashCode() : 0;
    }
//hashCode() in Object
public native int hashCode();

hashCode() is a method of Object. This method is to better support hash table. The reason why hashMap is fast in searching is that the bottom layer of hashMap uses hash table to generate array subscript according to the hashcode value of key (direct search through memory address, no judgment is needed, but a lot of memory needs to be added, which is equivalent to space for time).

3. What is the hash value? What is the function of the hashcode() method?

Each object has a hash value. By converting the physical address of the object to an integer, the integer can be hash calculated. Hash value exists mainly to improve the performance of lookup. Such hash sets include HashSet, HashMap and HashTable. When inserting a collection, duplicate elements are not allowed in the collection, which raises a question: how to judge whether the object already exists in the collection?

The first method that comes to mind is to call the equals() method, which is really feasible. But if there are a large number of data or more data in the set, if we use the equals method to compare one by one, the efficiency must be a problem. At this time, the function of the hashCode method is reflected. When a collection wants to add a new object, first call the hashCode method of the object to get the corresponding hash value. In fact, the hash value of each Entry object will be saved in the hashMap. If there is no hash value in the hash table, it will be stored directly. If there is a hash value, call the equals method to compare with the new element, which is the same. In this case, the old value will be overwritten with the new value, and other addresses will be hashed if they are different, so the number of actual calls to equals method will be greatly reduced.

This also explains why equals() is equal, then hashCode() must be equal. If the two objects equals(), they should only appear once in the hash table (such as HashSet, HashMap, etc.); if the hashCode() is not equal, they will be hashed to different positions in the hash table, and they appear multiple times in the hash table, which violates the design rules of the hash table.

So the existence of hashCode method is to reduce the number of calls of equals method and improve the program efficiency.

Finally, I will write an example to explain the classic question in the previous article: why rewrite equals() and hashcode()?

public class Persion {
	String name;

	public Persion(String name) {
		this.name = name;
	}

	public static void main(String[] args) {

		Map<Persion, String> map = new HashMap<Persion, String>();
		map.put(new Persion("SpiderMan"), "Spider-Man");
		System.out.println(map.get(new Persion("SpiderMan")));

	}

}
null

 

The logic we want to implement is: make the two objects consistent, because the name attribute is the same. When we use the key, we should return Spider Man "" according to the logic. If you do not override equals() and hashCode(), the above Demo will output null. The rewritten code is as follows:

public class Persion {
	String name;

	public Persion(String name) {
		this.name = name;
	}

	@Override
	public boolean equals(Object o) {

		if (this == o) {
			return true;
		}
		if (o == null || getClass() != o.getClass()) {
			return false;
		}
		
		Persion persion = (Persion) o;
		return Objects.equals(name, persion.name);
	}

	@Override
	public int hashCode() {
		return Objects.hash(name);
	}

	public static void main(String[] args) {

		Map<Persion, String> map = new HashMap<Persion, String>();
		map.put(new Persion("SpiderMan"), "Spider-Man");
		System.out.println(map.get(new Persion("SpiderMan")));

	}

}
Spider-Man

What if we want to realize that "Spider Man" or "Peter Parker" can be judged as "Spider Man"? The improved version is as follows:

public class Persion {
	String name;

	public Persion(String name) {
		this.name = name;
	}

	@Override
	public boolean equals(Object o) {

		if (this == o) {
			return true;
		}
		if (o == null || getClass() != o.getClass()) {
			return false;
		}
		
		Persion persion = (Persion) o;
		if("SpiderMan".equals(persion.name))
			return true;
		
		return Objects.equals(name, persion.name);
	}

	@Override
	public int hashCode() {
		if(name.equals("PeterParker")){
			return Objects.hash("SpiderMan");
		}
		return Objects.hash(name);
	}

	public static void main(String[] args) {

		Map<Persion, String> map = new HashMap<Persion, String>();
		map.put(new Persion("SpiderMan"), "Spider-Man");
		System.out.println(map.get(new Persion("SpiderMan")));
		System.out.println(map.get(new Persion("PeterParker"))); 

	}

}

 

Posted by docmattman on Sat, 26 Oct 2019 23:31:22 -0700