这篇总结的形式是提出个问题,然后给出问题的答案。这是目前学习知识的一种尝试,可以让学习更有目的。

Q1.什么时候应当重写对象的equals方法?
答:一般在我们需要进行值比较的时候,是需要重写对象的equals方法的。而例外情况在《effective java》的第7条“在改写equals的时候请遵守通用约定”中清楚描述了。
我们知道,在Java中,每个对象都继承于Object.如果不重写,则默认的equals代码如下所示:
public boolean euqals(Object obj){
return this == obj;
}
由上面的代码可以看出,equal默认是使用“==”来判断两个对象是否相等。两个对象使用“==”比较的是对象的地址,只有两个引用指向的对象相同的时候,“==”才返回true。所以,在开头的例子中,就需要重写equals方法,让两个对象有equals的时候。
Q2.如何重写equals?
答:首先,当改写equals方法时,需要保证满足它的通用约定。这些约定如下所示:
自反性,对于任意的引用值x,x.equals(x)一定为true。
对称性,对于任意的引用值x和y,当且仅当y.equals(x)时,x.equals(y)也一定返回true.
传递性,对于任意的引用值x,y,z。如果x.equals(y)返回true,y.euqals(z)返回true,则x.equals(z)也返回true。
一致性,对于任意的引用值x和y,如果用于equals比较的对象信息没有修改,那么,多次调用x.equals(y)要么一致返回true,要么一致返回false.
非空性,所有的对象都必须不等于null。
其实我觉的一个简单的方法是参照String的equals方法即可,官方出版,满足各种要求。其代码如下所示
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n– != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
函数的解释如下所示:
更详细的信息,还是请看《effective java》的第7条“在改写equals的时候请遵守通用约定”。
Q3.修改equals时需要注意什么?
答:大致需要注意以下几点:
若修改equals方法,也请修改hashCode方法
首先这个是语言的一个约定,这么做的一个原因是当此对象作为哈希容器的元素时,需要依赖hashCode,对象默认的hashCode是返回一个此对象特有的hashCode,不同的对象的hashCode返回值是不一样的,而哈希容器处理元素时,是按照对象的哈希值将对象分配到不同的桶中,若我们不重写对象的hashCode,那么值相等的对象产生的哈希值也会不同,这样当在哈希容器中查找时,会找不到对应的元素。
更详细的信息请看《effective Java》的第8条“改写equals时总是要改写hashCode”。
重写时保证函数声明的正确
请注意equals的声明是
public boolean equals(Object obj)
参数类型是Object,如果参数类型是此对象类型的话,如下:
class Point{
final int x;
final int y;
public void Point(int x, int y)
this.x = x;
this.y = y;
}
public boolean euqals(Point obj){
return (this.x == obj.x && this.y == obj.y);
}
}
下面代码执行是按照我们的预期执行的。
Point a(1, 2); Poinr b(1, 2); System.out.println(a.equals(b));// 输出true
但是如果将类A放入容器中,则会出问题
import java.util.HashSet; HashSet<Point> coll = new HashSet<Point>(); coll.add(a); System.out.println(coll.contains(b));// 输出false
这是由于HashSet中的contains方法中调用的是equals(Object obj),而Point中的equals(Object obj)仍是Object的equals,这个方法在前面已经说过了,比较的是对象的地址,所以在coll中调用contains(b)时,当然得不到true。
当有继承关系时注意equals的正确
当一个类重写equals方法后,另一个类继承此类,此时,可能会违反前面说到的对称性,代码如下所示:
public class ColoredPoint extends Point {
private final Color color;
public ColoredPoint(int x, int y, Color color) {
super(x, y);
this.color = color;
}
@Override
public boolean equals(Object other) {
boolean result = false;
if (other instanceof ColoredPoint) {
ColoredPoint that = (ColoredPoint) other;
result = (this.color.equals(that.color) && super.equals(that));
}
return result;
}
}
当我们作比较时
Point p = new Point(1, 2); ColoredPoint cp = new ColoredPoint(1, 2, Color.RED); System.out.println(p.equals(cp)); //输出ture System.out.println(cp.equals(p)); //输出false
原因是当调用Point.equals的时候,只比较了Point的x和y坐标,同时ColoredPoint也是Point类型,所以上面第三行代码相等,而调用ColoredPoint的时候,Point不是ColoredPoint类型,这样就导致第四行代码输出false。
若我们忽略Color的信息来比较呢,例如将ColoredPoint的equals方法改为:
@overwrite
public boolean equals(Object obj){
if((obj instanceof Point)){
return false;
}
if(!(obj instanceof ColoredPoint)){
return obj.equals(this);
}
return super.equals(obj) && ((ColoredPoint)obj).color == color;
}
这样就保证了对称性,但是却违反了传递性,即下面的情况:
ColoredPoint cp1 = new ColoredPoint(1, 2, Color.RED); Point p = new Point(1, 2); ColoredPoint cp2 = new ColoredPoint(1, 2, Color.BLUE); System.out.println(cp1.equals(p)); //true System.out.println(p.equals(cp2)); //true System.out.println(cp1.equals(cp2)); //false
面对这种情况,大致有两种解决方案,一种酷壳的文章–如何在Java中避免equals方法的隐藏陷阱的最后一条,断绝了Point和ColoredPoint相等的可能,这是一种处理方法,认为Point和ColoredPoint是不同的。另一种方法是effective Java上提出的,使用聚合而不是继承,将Point作为ColoredPoint的一个成员变量。目前我倾向于这种方法,因为聚合比继承更灵活,耦合更低。这种方法的代码如下所示:
class ColoredPoint{
private final Point point;
private final Color color;
public Point asPoint(){
return point;
}
public boolean equals(Object obj){
boolean ret = false;
if(obj instanceof ColoredPoint){
ColoredPoint that = (ColoredPoint)obj;
ret = that.point.equals(point) && color.equals(that.color);
}
return ret;
}
}
当ColoredPoint需要比较坐标时,可以调用asPoint方法来转化为坐标进行比较。其他情况比较坐标和颜色,这样就可以解决上面关于对称性和传递性的问题了。
以上就是全文的内容,由于水平有限,文章中难免会有错误,希望大家指正,谢谢。
希望本文对大家的学习有所帮助,也希望大家多多支持。
# Java
# Equals
# 30条Java代码编写经验分享
# JavaScript Base64 作为文件上传的实例代码解析
# JavaScript实现定时页面跳转功能示例
# javaScript嗅探执行神器-sniffer.js
# Java中request对象常用方法汇总
# 出现java.util.ConcurrentModificationException 问题及解决办
# Javascript下拉刷新的简单实现
# java Class.getSimpleName() 详解及用法
# java 单播、广播、组播详解及实例代码
# 重写
# 所示
# 的是
# 这是
# 会有
# 这种方法
# 也会
# 就不
# 什么时候
# 请遵守
# 说到
# 要注意
# 更有
# 仍是
# 此类
# 这种情况
# 希望大家
# 几点
# 请注意
# 可以看出
相关文章:
小自动建站系统:AI智能生成+拖拽模板,多端适配一键搭建
php8.4新语法match怎么用_php8.4match表达式替代switch【方法】
怎么用手机制作网站链接,dw怎么把手机适应页面变成网页?
湖北网站制作公司有哪些,湖北清能集团官网?
如何用5美元大硬盘VPS安全高效搭建个人网站?
安云自助建站系统如何快速提升SEO排名?
如何在IIS7中新建站点?详细步骤解析
哈尔滨网站建设策划,哈尔滨电工证查询网站?
学校为何禁止电信移动建设网站?
如何在建站宝盒中设置产品搜索功能?
建站之星如何配置系统实现高效建站?
c# 在ASP.NET Core中管理和取消后台任务
建站之星与建站宝盒如何选择最佳方案?
贸易公司网站制作流程,出口贸易网站设计怎么做?
如何选择靠谱的建站公司加盟品牌?
c++怎么使用类型萃取type_traits_c++ 模板元编程类型判断【方法】
建站之星安装后界面空白如何解决?
建站主机与虚拟主机有何区别?如何选择最优方案?
如何快速重置建站主机并恢复默认配置?
Swift开发中switch语句值绑定模式
青岛网站设计制作公司,查询青岛招聘信息的网站有哪些?
广州网站制作公司哪家好一点,广州欧莱雅百库网络科技有限公司官网?
如何在企业微信快速生成手机电脑官网?
如何通过虚拟机搭建网站?详细步骤解析
制作网站的软件下载免费,今日头条开宝箱老是需要下载怎么回事?
沈阳制作网站公司排名,沈阳装饰协会官方网站?
已有域名如何免费搭建网站?
宝塔面板如何快速创建新站点?
阿里云网站搭建费用解析:服务器价格与建站成本优化指南
如何批量查询域名的建站时间记录?
深圳网站制作的公司有哪些,dido官方网站?
如何在服务器上三步完成建站并提升流量?
广州营销型建站服务商推荐:技术优势与SEO优化解析
网站制作费用多少钱,一个网站的运营,需要哪些费用?
定制建站是什么?如何实现个性化需求?
平台云上自主建站:模板化设计与智能工具打造高效网站
如何通过多用户协作模板快速搭建高效企业网站?
设计网站制作公司有哪些,制作网页教程?
南平网站制作公司,2025年南平市事业单位报名时间?
如何快速查询网站的真实建站时间?
如何使用Golang安装API文档生成工具_快速生成接口文档
Android自定义控件实现温度旋转按钮效果
常州自助建站费用包含哪些项目?
开心动漫网站制作软件下载,十分开心动画为何停播?
高端建站如何打造兼具美学与转化的品牌官网?
如何快速生成专业多端适配建站电话?
公司网站的制作公司,企业网站制作基本流程有哪些?
家具网站制作软件,家具厂怎么跑业务?
专业网站建设制作报价,网页设计制作要考什么证?
c++如何打印函数堆栈信息_c++ backtrace函数与符号名解析【方法】
*请认真填写需求信息,我们会在24小时内与您取得联系。