The indissoluble bond between hashCode and equals

foreword

When I learned the core technology of java before, there was a section on hashCode and equals. In my impression, hashCode returns the memory address of the object. When the equals method is rewritten, the hashCode method should also be rewritten, and the degree of understanding is also different. This is limited to this, hashCode is commonly used in learning collections in the first two days, and it is more important to study hard when you come back.

HashCode

Why use hashCode? Check the official documentation

hashcode方法返回该对象的哈希码值。支持该方法是为哈希表提供一些优点,例如,java.util.Hashtable 提供的哈希表。 

hashCode 的常规协定是:
在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。 
如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。 
以下情况不 是必需的:如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用 hashCode 方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。 
实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。) 

当equals方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码

We can summarize the following points:

  • The meaning of hashCode is to search the hash table quickly. From the previous source code of HashMap, we can see that hashCode is necessary to calculate index, but it only calculates index. In the case of collision, hashCode is equal. Wrong, but their objects are not necessarily the same! So, in fact, the hashCode does not point to the real address! Do you have? just index

  • If the two objects are the same, equals will be the same True, and their hashcodes should be the same. When equals is rewritten, the hashcode will also be rewritten.

  • The same hashCode does not mean that the objects are the same! It just means that the index is the same, all in one bucket

Give a simple example to illustrate the power of hash lookup

The purpose of hashCode is to search.
  In the early stage of our study, what is the most basic search algorithm? You may say dichotomy, find the right one one by one, and then compare it with the stored content. Find them one by one, and the consumption must be huge. If you use hash, such as the search in HashMap , I find the index through the hash operation, the position of the bucket and then use equals to compare and search.
  Personally, I feel that many of the classes I have seen have the method of HashCode--it is specifically implemented, so there is no need to read this.

equals

Start with Object

1、Object.equals

    public boolean equals(Object obj) {
        return (this == obj);
    }

Object uses == instead of memory addresses

2、Objects.equals

    public static boolean equals(Object a, Object b) {
        return (a == b) || (a != null && a.equals(b));
    }

Objects.equals compares the address and the value returned by two objects equals

3、String.equals

    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String aString = (String)anObject;
            if (coder() == aString.coder()) {
                return isLatin1() ? StringLatin1.equals(value, aString.value)
                                  : StringUTF16.equals(value, aString.value);
            }
        }
        return false;
    }

Let's take a look at the actual equals override by looking at String, we can draw equals a few steps

1. Determine whether it is the same reference (same object)
2. Determine whether it is instanceof or getClass according to your own needs
3. Type coercion
4. Make your own comparison strategy

The comparison strategy of String is to compare the bytecode one by one, first judge the encoding, and then compare the encoding

    @HotSpotIntrinsicCandidate
    public static boolean equals(byte[] value, byte[] other) {
        if (value.length == other.length) {
            for (int i = 0; i < value.length; i++) {
                if (value[i] != other[i]) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }

One-to-one comparison of byte arrays of two values.

I have to mention that getClass is still instanceof

As for whether to use instanceof or getClass, it depends on the actual situation. You can use instanceof when you ignore the difference between the subclass and the parent class in practice, but if there is a difference between the parent class and the subclass, such as employee and manager, employee It is obviously inappropriate to have a relationship with the manager, see the example below

package compare;

import java.util.Objects;


public class Employee implements Comparable<Employee>
{
    private String name;
    private double salary;

    public Employee(String name, double salary)
    {
        this.name = name;
        this.salary = salary;
    }

    public String getName()
    {
        return this.name;
    }

    public double getSalary()
    {
        return this.salary;
    }

    @Override
    public boolean equals(Object otherObject)
    {
        if (otherObject == null) 
        {
            return false;
        }

        if (this == otherObject) 
        {
            return true;
        }

        if (this.getClass() != otherObject.getClass()) 
        {
            return false;
        }

        Employee other= (Employee) otherObject;

        return this.getSalary() == other.getSalary()
                && Objects.equals(getName(), getName());
    }

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

    @Override
    public String toString()
    {
        return getClass().getName() + "[ name: "+this.getName() + ", salary: " + this.getSalary() + " ]"; 
    }   
}

The comparison object of the employee here must be another employee. At the same time, the hashcode must be rewritten. Name and salary are used as parameters to ensure that equals are equal, and hashcodes are also equal.

Summarize

In general, the lookup of hashCode in the hash table plays an important role, and the rewrite of equals is to formulate a strategy to compare the equality of two objects. Only by really looking at the source code can we know their real role, java The hashcode is not a memory address! ! ! ! ! -Remember

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324738910&siteId=291194637