Java深入理解equals
在Java中Object类中的equals方法用于检测一个对象是否等于另一个对象。注意:这里的等于指的是两个对象的引用是否相等,即所谓的地址,这看起来好像没啥问题;不就是两个对象引用相等,则两对象相等!
但在实际开发中,往往是检测两对象的状态属性;
例如:如果两个学生的姓名,学号,年龄都一样,那就相等**(注意:实际上我们通常会结合数据库进行开发,真正的比较应该是主键(如id)),**因此我们需要重写equals方法,请看样例:
public class Student{
private int id;
private int age;
private String name;
//构造方法
public Student (int id,int age,String name){
代码省略
}
//省略了getter和setter
public static void main(String[] args){
var student1 = new Student(1,18,"luo");
var student2 = new Student(1,18,"luo");
student.equals(student3); //retuen true
//如果单纯的比比引用那这两个学生肯定不同
}
//重写的equals方法
public boolean equals(Object object){
if (this == obj)
return true;
if (obj == null)
return false;
if (this.getClass() != obj.getClass())
return false;
var other_student = (Student) obj;
return id = other_student.getId() &&
age = other_stuedet.getAge()&&
Objects.equals(name,other_student.getName());
}
}
如何重写equals?
引入
如果隐式参数和显示参数不属于同一个类,equals方法将如何处理?在上面例子中,只要发现类不匹配,就返回false。但是很多人喜欢这样:
if (!(obj instanceof Stuent))
return false;
这样写就允许obj属于一个子类但这中方法会招致一些麻烦(稍后会有解释),因为equals的一些规范
equals方法规范
- 自反性:见名知义
x.equals(x) return true
- 对称性:
:就好比 x.equals(y) ,y.equals(y) 的结果相同
- 传递性:
y.equals(z)返回true,x.equals(z)返回true 那么x.equals(y) 也应该返回true
- 一致性:如果x和y引用的对象没有发生变化,反复调用x.equals(y)应该的返回相同的结果。
这些规则都很合理,就对称性来说,当参数不属于同一类时会有一些微妙的结果,例如:
student.equals(person);
//student extends person
解释:如果这两个对象都有相同姓名,年龄,id。如果在Student.equals中调用instance进行检测:it will return true; 但是如果反过来调用:it will return false;
这样的情况,让人猛然觉得instance 是多么不方便!这就好比 x等于y,y却不等于x 这部扯淡吗!
instanceof 和getClass()
既然有人用instanceof ,存在即合理;上面的勿用现象其实实际情况都不理解: instanceof 和getclass()其实对应两种情况
- 如果子类可以有自己的相等性概念,则要按照对称性使用getClass()
- 如果子类有父类决定 相等性概念,那么就用instanceof检测,这样可以在不同的子类进行相等性比较
最后给出一个编写完美的equals方法的建议
- 检测this与otherObject 是否相等;(这条语句是一个优化,实际上,这是经常采用的一种形式。因为一开始检查引用身份要比逐个检查字段开销小)
- 检测otherObject 是否为null,如果为null,返回false.这项检测是非常有必要的
- 比较this与object类,如果子类有自己的相等性概念就用getclass检测
如果由父类决定相等性概念,那么就用instanceof检测 - 将显示参数Object强制转换相对应的类型变量:
- 比较各个成员·字段
具体如下:由于学生类具有自己的相等性概念 所以第3步采用 getClass()
public boolean equals(Object obj){
if (this == obj)
return true;
if (obj == null)
return false;
if (this.getClass() != obj.getClass())
return false;
var other_student = (Student) obj;
return id = other_student.getId() &&
age = other_stuedet.getAge()&&
Objects.equals(name,other_student.getName());
我曾经犯过的傻逼错误
public boolean equals(Stuedent obj){
if (this == obj)
return true;
if (obj == null)
return false;
if (this.getClass() != obj.getClass())
return false;
var other_student = (Student) obj;
return id = other_student.getId() &&
age = other_stuedet.getAge()&&
Objects.equals(name,other_student.getName());
大家应该知道错误在哪吧? 各位老哥就引以为戒吧! 为此,我们以后再重写方法时,最好添上一个@Override