We must first know that the Object class
is the parent class (super class/base class) of all classes in Java
, that is to say, in Java In
, all classes inherit from Object class
by default. In other words, we can use all the methods implemented in Object class
directly. The equals
method is one of the many methods implemented by the Object class
.
The following screenshots are taken from Java11 API
All methods of the Object class:
equals
: It is a method in Object class
. It can only determine the reference type. You can bring it later. Everyone, take a look at the jdk
source code
The default judgment is whether the addresses are equal (because the underlying essence of reference type variables is to store object addresses, those with C/C knowledge Friends should know it very well), this method is often overridden in subclasses to determine whether the contents of objects are equal. For example, Integer
and String
, which you will learn briefly later (see the source code implementation in IDEA)
We have the Object class
and the equals
method can be used, right? Why do we have to override the equals
method? This depends on the implementation mechanism of the equals
method of the Object class
.
We can clearly see that the bottom layer of the equals
method of the Object class
is implemented using ==, that is It is said that its usage is consistent with the usage of == which we usually use to compare basic data types. Let’s first take a look at the syntax of ==:
== can only be used to compare basic data types for equality, that is, simple value comparison;
== There may also be failures when comparing floating point numbers. This is because the storage mechanism of floating point numbers is different from that of the integer family. The floating point number itself cannot represent an accurate value (you can check the specific reasons by yourself). IEEE 754 rules, will not be expanded here)
So we can use == when simply comparing values of basic data types, but we cannot do this when comparing reference data types, as mentioned above It has been mentioned that the reference data type is essentially used to reference/store the address of the object, so you can treat it as a pointer to C/C
(here it is said that Java does not have pointers, personally I think it’s just a different name)
Note: Don’t confuse the Java
reference with the C
reference. The C reference is actually a pointer constant, that is, int* const
, this is why the reference of C
can only be used as an alias of a variable.
When comparing two ints, you can directly use ==. When they are equal, the result is true
, and when new
When two objects with exactly the same attributes are obtained, an error will occur if ==
is used for comparison. As we can see, we should obviously want to get true
, The result is false
Source code:
Running result:
Go here , we should have a rough idea of why we need to override the equals
method when comparing objects, because the Object class
provides us with something that is not easy to use~~
Before rewriting, let’s still take a look at the definition in Java API
: public boolean equals(Object obj)
Function: Indicates whether some other object is "equal" to this object.
The equals method implements equivalence on non-null object references:
Reflexivity: for any non-null reference value x
, x.equals(x)
should return true
.
Symmetry: For any non-null reference values x
and y
, x.equals(y)
should return true
if and only ify.equals(x)
returnstrue
.
Transitivity: For any non-null reference values x
, y
and z
, if x. equals(y)
returnstrue
y.equals(z)
returnstrue
, thenx.equals(z)
Should return true
.
Consistency: Multiple calls to x.equals(y)
always return for any non-null reference values x
and y
true
Or always return false
, provided that the information used in the equals
comparison on the object has not been modified.
For any non-null reference value x
, x.equals(null)
should return false
.
The equals method of class Object implements the most distinctive possible equivalence relationship on the object; that is, for any non-null reference values x and y, if and only if x and This method returns true when y refers to the same object (x == y has value true).
Note: It is usually necessary to override the hashCode method when overriding this method in order to maintain the normal contract of the hashCode
method, which states that equal objects must have equal hash codes.
Next look at the equals
method overridden in the String class
and the overridden Integer
class The equals
method written:
//String类equals源代码: public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }
A simple explanation is that when the comparison is the same object, it directly returns true
, Improve efficiency. When the object passed in is an instance of the current class, further judgment is entered. A for
loop traverses each character of the string in turn, and returns false
as long as one character is different.
Continue to take a look at the equals
source code of the Integer
class:
//Integer类的equals源代码: public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; }
Integer class
's equals
source code is much simpler. As long as the incoming object is an instance of the current class, further judgment will be made: when their values are equal, true
will be returned, otherwise If equal, return false
.
Let’s give a practical demonstration ⑧, taking the Integer class
as an example:
Obviously, we know Integer class
overrides the equals
method and is a reference type. When == is directly used to compare reference type variables, the result is false
, and equals
is used to determine the result is true
. This well illustrates the necessity of overriding the equals
method. String class
Please verify it yourself⑧.
(Let me talk about the conclusion first, getClass()
is safer than instanceof
)
At this point, we have basically analyzed the various source codes of the equals
method. The next step is to implement the equals
method ourselves.
Here are two common equals
rewriting methods:
Use instanceof
to implement rewriting equals
method
Use getClass
to implement overriding equals
method
Assume there are This scenario:
Override the equals
method in the Objec
t class in the already created rectangle class to return # when the length and width of the rectangle are equal. ##TRUE, while overriding the
hashCode method, and overriding the
toString method to display the length and width information of the rectangle. and test the class.
package com.test10_04; import java.util.Objects; class Rectangle { private double length; private double wide; public Rectangle() { //空实现 } public Rectangle(double length, double wide) { setLength(length); setWide(wide); } public double getLength() { return length; } public void setLength(double length) { assert length > 0.0 : "您的输入有误,长方形的长不能小于0"; this.length = length; } public double getWide() { return wide; } public void setWide(double wide) { assert wide > 0.0 : "您的输入有误,长方形的宽不能小于0"; this.wide = wide; } public double area() { return this.length * this.wide; } public double circumference() { return 2 * (this.wide + this.length); } public boolean equals(Object obj) { if (this == obj) { //判断一下如果是同一个对象直接返回true,提高效率 return true; } if (obj == null || obj.getClass() != this.getClass()) { //如果传进来的对象为null或者二者为不同类,直接返回false return false; } //也可以以下方法: // if (obj == null || !(obj instanceof Rectangle)) { //如果传进来的对象为null或者二者为不同类,直接返回false // return false; // } Rectangle rectangle = (Rectangle) obj; //向下转型 //比较长宽是否相等,注意:浮点数的比较不能简单地用==,会有精度的误差,用Math.abs或者Double.compare return Double.compare(rectangle.length, length) == 0 && Double.compare(rectangle.wide, wide) == 0; } public int hashCode() { //重写equals的同时也要重写hashCode,因为同一对象的hashCode永远相等 return Objects.hash(length, wide); //调用Objects类,这是Object类的子类 } public String toString() { return "Rectangle{" + "length=" + length + ", wide=" + wide + '}'; } } public class TestDemo { public static void main(String[] args) { Rectangle rectangle1 = new Rectangle(3.0, 2.0); Rectangle rectangle2 = new Rectangle(3.0, 2.0); System.out.println(rectangle1.equals(rectangle2)); System.out.println("rectangle1哈希码:" + rectangle1.hashCode() + "\nrectangle2哈希码:" + rectangle2.hashCode()); System.out.println("toString打印信息:" + rectangle1.toString()); } }The specific implementation ideas are clearly stated in the code. Let’s focus on analyzing the advantages and disadvantages of the two implementation methods
getClass and
instanceof:
Let’s focus on this simple code
//getClass()版本 public class Student { private String name; public void setName(String name) { this.name = name; } @Override public boolean equals(Object object){ if (object == this) return true; // 使用getClass()判断对象是否属于该类 if (object == null || object.getClass() != getClass()) return false; Student student = (Student)object; return name != null && name.equals(student.name); }
//instanceof版本 public class Student { private String name; public void setName(String name) { this.name = name; } @Override public boolean equals(Object object){ if (object == this) return true; // 通过instanceof来判断对象是否属于类 if (object == null || !(object instanceof Student)) return false; Student student = (Student)object; return name!=null && name.equals(student.name); } }In fact, both solutions are valid, the difference is
getClass() restricts the object to be the same class, but
instanceof allows the object to be the same class or its subclass, so the equals method becomes the parent class and subclass The equals operation can also be performed. At this time, if the subclass redefines the equals method, it may become the parent class object equlas. The subclass object is true, but the subclass object equlas the parent class object is false, as shown below:
class GoodStudent extends Student { @Override public boolean equals(Object object) { return false; } public static void main(String[] args) { GoodStudent son = new GoodStudent(); Student father = new Student(); son.setName("test"); father.setName("test"); // 当使用instance of时 System.out.println(son.equals(father)); // 这里为false System.out.println(father.equals(son)); // 这里为true // 当使用getClass()时 System.out.println(son.equals(father)); // 这里为false System.out.println(father.equals(son)); // 这里为false } }Note that
getClass() is used here
false , in line with our expectations, (even if the class is different, it must be
false)
instanceof Give it a try:
Running results: One is true
and the other is false
, obviously there is a problem.
The reasons here are as follows: The syntax of instanceof
is like this:
When an object is an instance of a class, the result Only then is true
. But it also has a characteristic that if this object is an instance of its subclass, the result will also be true
. This leads to the above bug. That is to say, when the two objects being compared have a parent-child relationship, instanceof
may cause problems. **Friends who need to learn more can learn it by themselves, so it is recommended that when rewriting the equals
method, try to use getClass
to achieve it.
When rewriting the equals
method, you need to override the hashCode
method.
The above is the detailed content of How to correctly override the equals method in Java. For more information, please follow other related articles on the PHP Chinese website!