Java-EE-Object 通用方法-equals()
概览
在Java中,所有的类默认继承自java.lang.Object
类,因此Object
类中定义的方法对于Java中的所有对象都是可用的。以下是Object
类的一些通用方法:
equals(Object obj)
:- 检查两个对象是否相等。默认实现比较的是对象的内存地址,但通常需要重写以提供有意义的比较逻辑。
toString()
:- 返回对象的字符串表示形式。默认实现返回对象的类名和哈希码的无符号十六进制表示,但通常需要重写以提供更有用的信息。
hashCode()
:- 返回对象的哈希码值。根据
equals
方法的重写,通常也需要重写hashCode
方法以保持一致性。
- 返回对象的哈希码值。根据
getClass()
:- 返回对象的
Class
对象,该对象表示对象的运行时类。
- 返回对象的
wait()
和wait(long timeout)
和wait(long timeout, int nanos)
:- 导致当前线程等待,直到另一个线程调用该对象的
notify()
或notifyAll()
方法,或者超过指定的时间。
- 导致当前线程等待,直到另一个线程调用该对象的
notify()
:- 唤醒在此对象监视器上等待的单个线程。
notifyAll()
:- 唤醒在此对象监视器上等待的所有线程。
clone()
:- 创建并返回对象的一个副本。默认实现会抛出
CloneNotSupportedException
,需要重写Cloneable
接口并实现该方法。
- 创建并返回对象的一个副本。默认实现会抛出
finalize()
:- 当垃圾回收器准备回收对象时调用此方法以进行清理。通常不推荐使用,因为Java 9开始已经过时。
这些方法为所有Java对象提供了基本的操作,很多方法在实际编程中都会根据需要被重写以实现特定的功能。例如,为了使对象能够正确地进行比较,通常会重写equals
和hashCode
方法。同样,为了提供对象的可读性更好的字符串表示,会重写toString
方法。
equals()
等价关系与实现
在Java中,equals()
方法是一个在java.lang.Object
类中定义的方法,用于检查两个对象是否相等。默认情况下,Object
类的equals()
方法实现是基于对象引用的比较,即它比较的是两个对象的内存地址是否相同。但是,对于需要根据对象内容来判断是否相等的情况,我们需要重写equals()
方法。
以下是equals()
方法的一些关键点:
- 重写
equals()
方法的规则:- 自反性:对于任何非空引用
x
,x.equals(x)
应该返回true
。 - 对称性:对于任何非空引用
x
和y
,x.equals(y)
应该等于y.equals(x)
。 - 传递性:对于任何非空引用
x
、y
和z
,如果x.equals(y)
返回true
,且y.equals(z)
返回true
,那么x.equals(z)
也应该返回true
。 - 一致性:对于任何非空引用
x
和y
,只要equals比较中所用的信息没有被修改,多次调用x.equals(y)
应该一致地返回true
或一致地返回false
。 - 与 null 的比较:对于任何非空引用
x
,x.equals(null)
应该返回false
。
- 自反性:对于任何非空引用
- 为什么要重写
equals()
方法:- 当对象的逻辑相等性不能通过比较内存地址来确定时,需要重写
equals()
方法。
- 当对象的逻辑相等性不能通过比较内存地址来确定时,需要重写
- 与
hashCode()
方法的关系:- 当重写
equals()
方法时,通常也需要重写hashCode()
方法,以保持equals()
和hashCode()
之间的一致性。如果两个对象通过equals()
方法比较是相等的,那么这两个对象调用hashCode()
方法也必须产生相同的整数值。
- 当重写
- 示例:
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
// 自反性
if (this == obj) {
return true;
}
// 检查是否为null
if (obj == null) {
return false;
}
// 检查是否是正确的类型
if (getClass() != obj.getClass()) {
return false;
}
// 强转并比较字段
Person other = (Person) obj;
return age == other.age && name.equals(other.name);
}
@Override
public int hashCode() {
// 根据对象的属性计算哈希码
int result = 17;
result = 31 * result + (name == null ? 0 : name.hashCode());
result = 31 * result + age;
return result;
}
}
在这个例子中,Person
类有两个属性:name
和age
。equals()
方法被重写,以确保当两个Person
对象具有相同的name
和age
时,它们被认为是相等的。同时,hashCode()
方法也被重写,以确保具有相同属性的Person
对象产生相同的哈希码。
equals() 与 ==
在Java中,==
运算符和equals()
方法都用于比较两个对象,但它们在比较方式和用途上存在明显的区别:
-
==
运算符:==
运算符用于比较两个对象的引用是否相等,即是否指向内存中的同一个对象。- 对于基本数据类型(如int、float、double等),
==
运算符比较的是值是否相等。 - 对于对象,
==
运算符比较的是两个引用是否指向同一个对象实例。
-
equals()
方法:equals()
方法是一个在Object
类中定义的方法,用于比较两个对象的逻辑相等性,即比较对象的内容是否相等。- 默认情况下,
equals()
方法比较的是对象的内存地址,但通常需要重写这个方法以提供更有意义的比较逻辑。 - 当重写
equals()
方法时,应该遵循非空性、等价性、对称性、传递性和一致性的原则。
区别:
==
是一个运算符,而equals()
是一个方法。==
比较的是对象的引用,而equals()
比较的是对象的逻辑相等性。==
对于基本数据类型是比较值,对于对象是比较引用;equals()
默认比较引用,但可以被重写以比较对象内容。equals()
方法可以被重写,以提供更复杂的比较逻辑,而==
运算符不能被重写。
使用场景:
- 当需要比较两个变量是否引用同一个对象时,使用
==
运算符。 - 当需要比较两个对象的内容是否相等时,使用
equals()
方法。
注意事项:
- 当重写
equals()
方法时,通常也需要重写hashCode()
方法,以保持equals()
和hashCode()
之间的一致性。这是因为很多数据结构(如HashMap、HashSet等)依赖于hashCode()
方法来快速定位对象。
示例:
String str1 = new String("hello");
String str2 = new String("hello");
String str3 = str1;
System.out.println(str1 == str2); // 输出 false,因为str1和str2是不同的对象
System.out.println(str1 == str3); // 输出 true,因为str3引用的是str1的对象
System.out.println(str1.equals(str2)); // 输出 true,因为str1和str2的内容相同
在这个例子中,str1
和str2
是两个不同的对象,所以str1 == str2
的结果是false
。而str3
引用的是str1
的对象,所以str1 == str3
的结果是true
。尽管str1
和str2
是不同的对象,但它们的内容相同,所以str1.equals(str2)
的结果是true
。