Java中Equals使用方法汇总

发布时间 - 2026-01-10 23:02:22    点击率:

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

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;
}

函数的解释如下所示:

  • 使用==检查“实参是否是指向对象的一个引用”。
  • 使用instanceof检查实参是否和本对象同类,如果不同类,就不相等。
  • 将实参转换为正确的类型。
  • 根据类的定义,检查实现此对象值相等的各个条件。

更详细的信息,还是请看《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 单播、广播、组播详解及实例代码  # 重写  # 所示  # 的是  # 这是  # 会有  # 这种方法  # 也会  # 就不  # 什么时候  # 请遵守  # 说到  # 要注意  # 更有  # 仍是  # 此类  # 这种情况  # 希望大家  # 几点  # 请注意  # 可以看出 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 通义万相免费版怎么用_通义万相免费版使用方法详细指南【教程】  动图在线制作网站有哪些,滑动动图图集怎么做?  Laravel如何使用Service Provider注册服务_Laravel服务提供者配置与加载  网站建设整体流程解析,建站其实很容易!  如何在自有机房高效搭建专业网站?  Android中Textview和图片同行显示(文字超出用省略号,图片自动靠右边)  Laravel中的withCount方法怎么高效统计关联模型数量  车管所网站制作流程,交警当场开简易程序处罚决定书,在交警网站查询不到怎么办?  Python面向对象测试方法_mock解析【教程】  Laravel如何实现API资源集合?(Resource Collection教程)  如何在Tomcat中配置并部署网站项目?  Laravel路由怎么定义_Laravel核心路由系统完全入门指南  Laravel distinct去重查询_Laravel Eloquent去重方法  如何在万网自助建站平台快速创建网站?  香港服务器网站生成指南:免费资源整合与高速稳定配置方案  如何快速上传自定义模板至建站之星?  移动端手机网站制作软件,掌上时代,移动端网站的谷歌SEO该如何做?  logo在线制作免费网站在线制作好吗,DW网页制作时,如何在网页标题前加上logo?  Laravel怎么发送邮件_Laravel Mail类SMTP配置教程  如何彻底删除建站之星生成的Banner?  Win11怎样安装网易有道词典_Win11安装词典教程【步骤】  Laravel如何使用模型观察者?(Observer代码示例)  利用 Google AI 进行 YouTube 视频 SEO 描述优化  Laravel如何安装Breeze扩展包_Laravel用户注册登录功能快速实现【流程】  Laravel如何实现全文搜索功能?(Scout和Algolia示例)  网站制作免费,什么网站能看正片电影?  佐糖AI抠图怎样调整抠图精度_佐糖AI精度调整与放大细化操作【攻略】  Laravel如何实现API速率限制?(Rate Limiting教程)  Laravel怎么做缓存_Laravel Cache系统提升应用速度的策略与技巧  iOS UIView常见属性方法小结  html5怎么画眼睛_HT5用Canvas或SVG画眼球瞳孔加JS控制动态【绘制】  如何在IIS管理器中快速创建并配置网站?  实现点击下箭头变上箭头来回切换的两种方法【推荐】  如何快速搭建个人网站并优化SEO?  ChatGPT回答中断怎么办 引导AI继续输出完整内容的方法  JS碰撞运动实现方法详解  韩国代理服务器如何选?解析IP设置技巧与跨境访问优化指南  如何基于云服务器快速搭建个人网站?  如何在阿里云服务器自主搭建网站?  Laravel如何实现邮件验证激活账户_Laravel内置MustVerifyEmail接口配置【步骤】  Laravel怎么创建自己的包(Package)_Laravel扩展包开发入门到发布  Laravel如何处理CORS跨域问题_Laravel项目CORS配置与解决方案  网站制作大概多少钱一个,做一个平台网站大概多少钱?  Laravel集合Collection怎么用_Laravel集合常用函数详解  java ZXing生成二维码及条码实例分享  Laravel如何处理异常和错误?(Handler示例)  Laravel PHP版本要求一览_Laravel各版本环境要求对照  如何在建站宝盒中设置产品搜索功能?  黑客入侵网站服务器的常见手法有哪些?  Angular 表单中正确绑定输入值以确保提交与验证正常工作