分析:要先了解==,hashCode()这两个内容,equals()中两者会涉及到。
1."=="运算符
= =是"相等",但分为两种情况:
引用类型:比较的是对象的内存地址是否相同。
Object obj=new Object();
Object ccc=new Object();
obj == ccc //false
基本类型:比较的是值,因为基础类型变量是直接存放值在栈中的。
int a=100; int b=100;
a==b //true
2.hashCode()方法
hashCode()方法是用来返回对象的散列值的,是Object类的一个方法,具体概念这里就不说了,Google.
java有个规范:两个对象如果equals()返回值为true,这两个对象的散列值应该相等。
3.equals()方法
equals()方法是Object类的方法,基本类型变量是没有equals()方法的!!
官方文档上描述equals()有五个特点:
1.自反性:对象a.equals(a)返回值永远都为true;
2.对称性:即有两对象a,b; a.equals(b)和b.equals(a)返回值是一样的;
3.传递性:有对象a,b,c; a.equals(b)为true,a.equals(c)为true,则b.equals(c)为true;
4.一致性:即多次调用equals方法,结果不变,a.equals(b)==a.equals(b);
5.对于null:所有不为null的对象a, a.equals(null)结果都为false; (null.equals(null)会报空指针异常的)
Object类是java所有类的基类,所有的类可以重写equals方法,所以一般可以把equals方法分为两种情况:
1.没有重写equals方法,使用父类Object的原始equals()方法。
2.重写equals方法,通常有必要重写hashcode().(java语言的规范)。
1.先介绍Object的equals方法,源码如下:
public boolean equals(Object obj) {
return (this == obj);
}
从源码我们可以看出,Object类的equals()方法是和"= ="运算符一样的。所以类没有重写equals方法的话,equals() 和= =完全一样。
示例代码:
public class Car{
private int size;
private int speed;
public Car(){}
public Car(int size,int speed){
this.size=size;
this.speed=speed;
}
//get、set方法省略就不贴上了
}
--------------------------------------
public class Test{
public static void main(String[] args){
Car bmw=new Car(4,60);
Car ben=new Car(4,60);
System.out.println(bmw==ben); //false
System.out.println(bmw.equals(ben)); //false
}
}
**说明:new 一个对象会在堆里面存放一个实例,引用变量(bmw,ben)存放的是对应的地址,所以虽然两个对象表面上看是等价的,但是内存地址不一样。
然而,我们有时候需求是比较两个对象的各个属性值相等就看作等价,该怎么办呢?
这时候我们就要重写equals()方法了。上面第2点提到了,重写了equals方法,也需要重写hashCode()方法(原因也在后面)。
2.重写equals方法。
实例代码
public class Car{
private int size;
private int speed;
public Car(){}
public Car(int size,int speed){
this.size=size;
this.speed=speed;
}
@override
public boolean equals(Object obj){
if(this==obj) return true; //先检查是不是同一个对象的引用
if(obj==null || this.getClass() != obj.getClass()) return false;
//再检查是否为null,(任何不为null对象equals(null)都返回false)
//再检查两个对象是否为同一个类,不是则返回false。
Car car=(Car)obj;
if(this.size!=obj.size) return false;
return this.speed==obj.speed;
//假如我们没有重写hashCode方法
}
}
--------------------------------------------
public class Test{
public static void main(String[] args){
Car bmw=new Car(4,60);
Car ben=new Car(4,60);
System.out.println(bmw==ben); //false
System.out.println(bmw.equals(ben)); //true
}
上面代码也可以再次体会equals()方法 和 == 运算符的区别。
equals()方法是可以改变的,根据自己的需求,那为什么说equals()方法重写后,一般有必要重写hashCode()方法?
这就联系到java中的集合部分。
上述重写例子两个对象,这两个对象我们设计equals()方法判断他们是等价的,我们希望在集合中只添加一个对象,如果散列值不同,集合中会添加两个等价对象。
参考
在java中,大家可以查看包装类,和String类的源码。他们都重写了equals()方法和hashCode()方法。 包装类还涉及到缓存池的内容,值得大家好好去看看,能对其有更好的理解。
String类:
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;
}
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
总结
equals()是一个方法,我们可以根据自己的需求重写这个方法。 一般就是重写为判断两个对象所有属性值都相同则为等价,否则equals这个取名就没有意义了。
而==运算符 对于引用类型来说就是比较两个对象的内存地址。
对于基本类型来说,就是比较两个基本类型变量的值了。 具体可以参考周志明的《深入理解java虚拟机》,底层的东西才是基础。
equals方法被重写,hashCode()也应该重写。保持两个对象等价,散列值相等的原则。
分享一个大佬的博客:https://github.com/CyC2018/CS-Notes
你会受益匪浅的!