The equals() and hashcode() methods for object comparison in Java

Posted by 28rain on Tue, 18 Jan 2022 22:33:57 +0100

equals() and hashcode() in Java object comparison

1. Comparison and analysis of equals() method and "= ="

First, put forward a misunderstanding:

  • ==Address comparison during comparison
  • Values are compared when equals is compared
String a = "123";
String b = "123";
System.out.println(a.equals(b)); // true
System.out.println(a == b); // true

String a1 = new String("123");
String b1 = new String("123");
System.out.println(a1.equals(b1)); // true
System.out.println(a1 == b1); // false

It seems no problem.

However, after reading the source Object class, I found that the default equals method in the Object compares addresses

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

After reading the source String class, you can find that the equals method is rewritten in the String class, overwriting the equals method of Object, so the equals of String is a value comparison!

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;
}

Therefore, equals() does not necessarily compare values. When using a self created class, if you want to compare values, you must override the equals() method.

2. How should I override the equals method

  • (1) The purpose of overriding the equals method:

Overriding equals is performed when two objects are considered equal when some fields of the two objects are equal

  • (2) To rewrite a perfect equals():

1. The explicit parameter is named otherObject, which will be cast to another variable named other later
2. Check whether this and otherObject are equal
3. Check whether otherObject is null
4. Compare the classes of this and otherObject. If the semantics of equals can be changed in subclasses, use getclass to detect
If all subclasses have the same equality semantics, instanceof detection is used
5. Cast otherObject to a variable of corresponding class type
6. Use = = compare the basic type field with object Equals comparison object field

by <core Java>

Note:

The type checking rule of instanceof is: you belong to this class or the derived class of this class;
getClass gets the type information and uses = = to check whether it is equal. It is a strict judgment, and only "this class" will be judged

example:

When two people are the same age, we think the two objects are the same:

class Person {
    private int age;
    private String name;

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age;
    }

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

test:

Person p1 = new Person(15, "Mary");
Person p2 = new Person(15, "Mark");
System.out.println(p1.equals(p2)); // true
System.out.println(p1 == p2); // false

3. Why should hashcode() be overridden when equals() is overridden

You can see that in the above program, not only the equals() method but also the hashcode() method is rewritten:

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

To rewrite equals, you'd better rewrite hashcode(), hash some fields to be compared (), that is, get the corresponding hash value through a hash function

Why?

In fact, this is to improve the efficiency of the program:

If you don't rewrite hashcode(), you can imagine that inserting a new element into a collection with 10000 elements requires comparing the previous 10000 elements. For each comparison, you need to call equals() to compare each field to be compared. You can easily imagine that the time and complexity of the comparison are huge.

If you insert elements, you can quickly judge whether there are the same elements in the set through the search of hashcode, and you can solve the problem of set insertion in O(1) time.

At the same time, rewriting hashcode() also ensures that when the object equals, if it is true, its corresponding hashcode must be equal. Although not rewriting hashcode() when it does not involve collection operations does not affect the comparison, and the compilation run will not report errors, it will violate the comparison rules of objects in Java.

Important specifications for these two methods:

Specification 1: if the equals(Object obj) method is rewritten, it is necessary to rewrite the hashcode() method to ensure that the two objects that are judged to be true by the equals(Object obj) method have equal hashcode() return values. To put it simply, "if two objects are the same, their hashcodes should be equal.". However, please note that this is only a specification. If you have to write a class so that equals(Object obj) returns true and hashcode() returns two unequal values, there will be no error in compilation and operation. However, this violates the Java specification, and the program buries a BUG.

Specification 2: if equals(Object obj) returns false, that is, the two objects are "different", it is not required to call the hashcode() method on the two objects to get two different numbers. Simply put, "if two objects are different, their hashcodes may be the same.".

Original link: https://blog.csdn.net/hla199106/article/details/46907725

over

Topics: Java object hashcode