The equals method in the Object class is used to detect whether an object is equal to another object. In the Object class, this method determines whether two objects have the same reference. If the two objects have the same reference, they must be equal. From this point of view, it is reasonable to use it as the default operation. However, for most classes, this judgment is meaningless. For example, it is completely meaningless to compare whether two PrintStreams are equal in this way. However, it is often necessary to detect the equality of the states of two objects. If the states of the two objects are equal, the two objects are considered equal. Therefore, in general, equals comparisons must be rewrite in custom classes.
Here are some suggestions for writing a perfect equals() method:
(1) The explicit parameter is named otherObject, and it needs to be converted into a variable called other later
(2) Detect whether this and otherObject refer to the same object:
if(this==otherObject) return true;
This statement is just an optimization. In fact, this is a form that is often adopted. Because calculating this equation is much less expensive than comparing the fields in a class one by one.
(3) Check whether otherObject is null, and if null, return false. This test is necessary.
if(otherObject==null) return false;
(4) Compare whether this and otherObject belong to the same class. If the semantics of equals change in each subclass, use getClass() to detect it, which takes itself as the target class
if(getClass()!=otherObject.getClass()) return false;
If all subclasses have the same semantics, use instanceof detection
if(!(otherObject instanceof ClassName)) return false;
(5) Convert otherObject to a variable of the corresponding type:
ClassName other=(ClassName)otherObject;
(6) Now start comparing all domains that need to be compared. Use == to compare the basic type domain, and use equals to compare the object domain. Return true if all fields match, otherwise return false;
return field1==other.field1&&field2.equals(other.field2)
If equals is redefined in a subclass, you must include the call super.equals(other). If the detection fails, it is impossible to be equal. If the domains in the superclass are equal, compare the instance domains in the subclass.
For array-type fields, you can use the static Arrays.equals method to detect whether the corresponding elements are equal.
Let’s take a look at some comparison examples of strings:
String a = "abc"; String b = "abc"; String c = new String("abc"); String d = new String("abc"); System.out.println(a == b); // true Because string constants are shared in JAVA, there is only one copy System.out.println(a == c); // false a and c belong to 2 different objects System.out.println(a.equals(c)); // true Since the equals method of the String object compares the values in the object, it returns true. (Different from the Object's equals method) System.out.println(c==d); // false Although the values in the objects are the same, they belong to 2 different objects, so they are not equal System.out.println(c.equals(d)); // trueSimply put, when comparing string constants, it is the same as the result returned by equals. When you want to compare the value of the string object, use equals.
See an example of using equals:
package chapter05.EqualsTest; import java.util.*; public class EqualsTest { public static void main(String[] args) { Employee alice1 = new Employee("Alice Adams", 75000, 1987, 12, 15); Employee alice2 = alice1; // reference the same object Employee alice3 = new Employee("Alice Adams", 75000, 1987, 12, 15); Employee bob = new Employee("Bob Brandson", 50000, 1989, 10, 1); System.out.println("alice1 == alice2: " + (alice1 == alice2)); System.out.println("alice1 == alice3: " + (alice1 == alice3)); System.out.println("alice1.equals(alice3): " + (alice1.equals(alice3))); System.out.println("alice1.equals(bob): " + (alice1.equals(bob))); System.out.println(bob.toString()); } } class Employee { public Employee(String n, double s, int year, int month, int day) { name = n; salary = s; GregorianCalendar calendar = new GregorianCalendar(year, month, day); hireDay = calendar.getTime(); } public String getName() { return name; } public double getSalary() { return salary; } public Date getHireDay() { return hireDay; } public void raiseSalary(double byPercent) { double raise = salary * byPercent / 100; salary += raise; } @Override public boolean equals(Object otherObject) { // a quick test to see if the objects are identified if (this == otherObject) return true; // must return false if the explicit parameter is null if (otherObject == null) return false; // if the classed don't match,they can't be equal if (getClass() != otherObject.getClass()) return false; // now we know otherObject is a non-null Employee Employee other = (Employee) otherObject; // test whether the fields hava identified values return name.equals(other.name) && salary == other.salary && hireDay.equals(other.hireDay); } @Override public int hashCode() { return 7 * name.hashCode() + 11 * new Double(salary).hashCode() + 13 * hireDay.hashCode(); } @Override public String toString() { return getClass().getName() + "[name=" + name + ",salary=" + salary + ",hireDay=" + hireDay + "]"; } private String name; private double salary; private Date hireDay; } class Manager extends Employee { public Manager(String n, double s, int year, int month, int day) { super(n, s, year, month, day); bouns = 0; } @Override public double getSalary() { double baseSalary = super.getSalary(); return baseSalary + bouns; } public void setBouns(double b) { bouns = b; } @Override public boolean equals(Object otherObject) { if (!super.equals(otherObject)) return false; Manager other = (Manager) otherObject; // super equals checked that this and other belong to the same class return bouns == other.bouns; } @Override public int hashCode() { return super.hashCode() + 17 * new Double(bouns).hashCode(); } @Override public String toString() { return super.toString() + "[bouns=" + bouns + "]"; } private double bouns; } Go deeper and divide it into 2 categories according to "whether the class overrides the equals() method".
(1) If a class does not override the equals() method, when it compares the two objects through equals(), it is actually comparing whether the two objects are the same object. At this time, it is equivalent to comparing these two objects by "==".
(2) We can override the equals() method of the class to let equals() compare whether two objects are equal in other ways. The usual practice is: if the contents of two objects are equal, the equals() method returns true; otherwise, it returns fasle.
Next, let us give an example to explain the above two situations.
1. The case of "Not overriding equals() method"
The code is as follows (EqualsTest1.java):
import java.util.*;import java.lang.Comparable;/** * @desc equals() test program. */public class EqualsTest1{ public static void main(String[] args) { // Create 2 new Person objects with the same content, // Use equals to compare whether they are equal Person p1 = new Person("eee", 100); Person p2 = new Person("eee", 100); System.out.printf("%s/n", p1.equals(p2)); } /** * @desc Person class. */ private static class Person { int age; String name; public Person(String name, int age) { this.name = name; this.age = age; } public String toString() { return name + " - " +age; } }} Running results:
Copy the code as follows: false
Results analysis We use p1.equals(p2) to "compare whether p1 and p2 are equal." In fact, the equals() method of Object.java is called, that is, the (p1==p2) called. It is to compare "whether p1 and p2 are the same object".
From the definitions of p1 and p2, we can see that although their content is the same, they are two different objects! Therefore, the return result is false.
2. The situation of "overwriting equals() method"
We modify the EqualsTest1.java above: override the equals() method.
The code is as follows (EqualsTest2.java):
import java.util.*;import java.lang.Comparable;/** * @desc equals() test program. */public class EqualsTest2{ public static void main(String[] args) { // Create 2 new Person objects with the same content, // Use equals to compare whether they are equal Person p1 = new Person("eee", 100); Person p2 = new Person("eee", 100); System.out.printf("%s/n", p1.equals(p2)); } /** * @desc Person class. */ private static class Person { int age; String name; public Person(String name, int age) { this.name = name; this.age = age; } public String toString() { return name + " - " +age; } /** * @desc Override equals method*/ @Override public boolean equals(Object obj){ if(obj == null){ return false; } //If it is the same object, return true, otherwise return false if(this == obj){ return true; } //Judge whether the type is the same if(this.getClass() != obj.getClass()){ return false; } Person person = (Person)obj; return name.equals(person.name) && age==person.age; } }} Running results:
Copy the code as follows: true
Results analysis:
We override Person's equals() function in EqualsTest2.java: when the name and age of the two Person objects are equal, it returns true.
Therefore, the run result returns true.
Having said that, let’s talk about Java’s requirements for equals(). There are the following points:
Symmetry: If x.equals(y) returns "true", then y.equals(x) should also return "true".
Reflectivity: x.equals(x) must return "true".
Analogy: If x.equals(y) returns "true", and y.equals(z) returns "true", then z.equals(x) should also return "true".
Consistency: If x.equals(y) returns "true", as long as the contents of x and y remain unchanged, no matter how many times you repeat x.equals(y), the return will be "true".
Non-empty, x.equals(null), always returns "false"; x.equals (objects of different types and x) always returns "false".
Now, let’s review the role of equals(): determine whether two objects are equal. When we rewrite equals(), it is impossible to change its function!
What is the difference between equals() and ==?
== : Its function is to determine whether the addresses of two objects are equal. That is, determine whether the two objects are the same object.
equals() : Its function is to determine whether two objects are equal. However, it generally has two usage conditions (it has been described in detail in the previous part 1):
Case 1, the class does not override the equals() method. Then when comparing two objects of this class through equals(), it is equivalent to comparing these two objects by "==".
Case 2, the class overrides the equals() method. Generally, we override the equals() method to make the contents of two objects equal; if their contents are equal, it returns true (that is, the two objects are considered equal).
Below, compare their differences by examples.
The code is as follows:
import java.util.*;import java.lang.Comparable;/** * @desc equals() test program. */public class EqualsTest3{ public static void main(String[] args) { // Create 2 new Person objects with the same content, // Use equals to compare whether they are equal Person p1 = new Person("eee", 100); Person p2 = new Person("eee", 100); System.out.printf("p1.equals(p2) : %s/n", p1.equals(p2)); System.out.printf("p1==p2 : %s/n", p1==p2); } /** * @desc Person class. */ private static class Person { int age; String name; public Person(String name, int age) { this.name = name; this.age = age; } public String toString() { return name + " - " +age; } /** * @desc Override equals method*/ @Override public boolean equals(Object obj){ if(obj == null){ return false; } //If it is the same object, return true, otherwise return false if(this == obj){ return true; } //Judge whether the type is the same if(this.getClass() != obj.getClass()){ return false; } Person person = (Person)obj; return name.equals(person.name) && age==person.age; } }} Running results:
p1.equals(p2): truep1==p2: false
Results analysis:
In EqualsTest3.java:
(1) p1.equals(p2)
This is to determine whether the contents of p1 and p2 are equal. Because Person overrides the equals() method, and this equals() is used to determine whether the contents of p1 and p2 are equal, exactly the contents of p1 and p2 are equal; therefore, return true.
(2) p1==p2
This is to determine whether p1 and p2 are the same object. Since they are two new Person objects each; therefore, return false.