搜索
首页Javajava教程关于java覆盖equals更深层的方法概述

最近和同事谈到equals和==的区别。这其实是个非常老套简单的问题,但当你要亲自覆盖equals方法时,才发现,有一些你不知道却又不得不知道的事。覆盖equals,讲究很多。尽管Object是一个很具体的类,但是他的主要作用还是为了扩展。他的所有非final方法都有着明确的通用约定。因为他们被设计成要被覆盖的方法。任何一个类,在覆盖equals、hashCode、toString、clone、finalize时,都有责任遵守这些方法的通用约定。如果不能做到这一点,那么当多个类组合时将难以发挥我们期望的效果。

不覆盖equals方法


覆盖equals方法看起来简单,但是有许多覆盖方法会导致错误。最容易避免这种错误的方法就是不覆盖equals,这种情况下每个类的实例都只与自身相等。那么在什么情况下我们可以选择不覆盖equals方法呢?

类的每个实例本质上是唯一的

对于代表活动实体而不是值的类来说确实如此,比如每个线程实例。我们用equals方法比较他是毫无意义的,因为每个线程是唯一的。在这种情况下,我们不用覆盖equals方法,因为Object类中的equals已经完全够用了。

Object类中equals方法实现:

 public boolean equals(Object obj) { return (this == obj);  }

不关心类是否需要逻辑相等的判断

有些类是一些“数值类”,比较大小,数学运算是这些类的本职工作。在这种情况下,需要我们将类中存放的数值进行比较,需要进行逻辑相等的判断。除此之外的类,很大部分类没有“一个是否等于另外一个”的概念。这种不关心逻辑相等的类不需要覆盖equals方法。

超类实现的equals对子类适用

举个例子,继承了AbstractSet类的HashSet类在equals方法上并没有任何区别,那么HashSet直接使用AbstractSet的equals方法即可。

覆盖equals方法

与上面的内容相反的,我们需要覆盖equals方法的情况就是:如果类具有自己的逻辑相等的概念,并且父类没有进行可用的equals方法覆盖。这时需要我们亲自进行覆盖。

集合中equals方法的等价关系


equals方法实现了等价关系。离散数学中学习过等价关系的概念,对于一个R上的二元关系,如果它满足自反对称和传递,那么他就是等价的。我们来具体分析一下equals和这三种性质的关系。

自反性 : 对于任何非null的引用值x,x.equals(x)必须返回true

对称性 : 对于任何非null的引用值x和y,当且仅当y.equals(x)返回 true时,x.equals(y)必定返回true

传递性 : 对于任何非null的引用值x、y和z,如果x.equals(y)返回true、y.equals(z)也返回true,那么x.equals(z)必定返回true。

自反性:∀ a ∈A, => (a, a) ∈ R
对称性:(a, b) ∈R∧ a ≠ b => (b, a)∈R
传递性:(a, b)∈R,(b, c)∈R =>(a, c)∈R

对比一下这三个性质,没有任何问题。由此可得,equals方法实现了等价关系。

如何编写equals方法


Object的equals方法只是简单的看看地址,这显然不可能满足我们的要求。那么在自己编写equals方法进行覆盖时如何才能保证编写出高质量的,逻辑比较的方法呢?equals的编写可以概括为下面四步:

1.使用==操作符检查参数是否只是对象的引用
如果结果相等则返回true,说明x与y是一个对象的不同引用,不需要再进行判断了。

2.使用instanceof操作符检查参数是否类型正确
如果结果不是正确的类型则返回false,因为我们的equals方法是继承自Object类的,所以参数的类型无法避免的是Object,我们先使用instanceof对参数进行类型判断,如果类型都不正确,就不用进行下一步判断了。

3.把参数转换成正确的类型
因为之前做了检测,所以这一步的类型转换没有问题。

4.对每个类中需要逻辑比较的域值进行判断
已经确保x和y是相同类型的不同实例,将需要判断的逻辑比较的域值取出进行比较判断即可。如果全部正确则返回true,否则返回false。

关于实现的equals需要注意的问题


当编写完equals方法后,一定要反复的判断是否符合自反性,对称性和传递性。不仅仅如此,在确保等价的情况下,编写equals方法时还有一些值得注意的事情,我们需要以此改进。

覆盖equals方法时总要覆盖hashCode方法
如果我们在编写有关散列的类时,必须在覆盖equals方法时覆盖hashCode方法。因为在散列表中,逻辑相同的对象应该具有相同的散列码。举个比较简单的例子:将String存入HashSet,有可能两个内容相同的String字串用==判断为false,但是他们在HashSet中只存在了一份。这就是因为逻辑相同的String拥有这相同的hashCode。
普遍性的,如果你为你的类覆盖了equals方法,那么证明在某种情况下会有两个不同对象是逻辑相等的。此时如果与散列相关,那么这两个对象需要相同的hashCode。所以覆盖equals方法时总要覆盖hashCode方法。

不要让equals方法过于智能
如果我们只是简单的按照上面的实现流程来编写equals的方法,既符合规定也不会导致奇怪的错误。但是如果我们非要去追求各种各样、花哨的等价关系,而把代码搞得臃肿不堪,那么既违反了高内聚的初衷,也会让代码出一些莫名其妙的错误。

不要将equals方法的参数类型弄错
说出来可能感觉好笑,但这确实是会发生的情况。修改了参数类型之后的equals方法已完全于Object类没有了关系,编译器不会报错,留下的只是给程序员无尽的头痛。如果不能意识到参数类型是Object,很有可能花费几个小时也搞不清程序为什么不能正常工作。

最近和同事谈到equals和==的区别。这其实是个非常老套简单的问题,但当你要亲自覆盖equals方法时,才发现,有一些你不知道却又不得不知道的事。覆盖equals,讲究很多。尽管Object是一个很具体的类,但是他的主要作用还是为了扩展。他的所有非final方法都有着明确的通用约定。因为他们被设计成要被覆盖的方法。任何一个类,在覆盖equals、hashCode、toString、clone、finalize时,都有责任遵守这些方法的通用约定。如果不能做到这一点,那么当多个类组合时将难以发挥我们期望的效果。

不覆盖equals方法


覆盖equals方法看起来简单,但是有许多覆盖方法会导致错误。最容易避免这种错误的方法就是不覆盖equals,这种情况下每个类的实例都只与自身相等。那么在什么情况下我们可以选择不覆盖equals方法呢?

类的每个实例本质上是唯一的

对于代表活动实体而不是值的类来说确实如此,比如每个线程实例。我们用equals方法比较他是毫无意义的,因为每个线程是唯一的。在这种情况下,我们不用覆盖equals方法,因为Object类中的equals已经完全够用了。

Object类中equals方法实现:

 public boolean equals(Object obj) { return (this == obj);  }

不关心类是否需要逻辑相等的判断

有些类是一些“数值类”,比较大小,数学运算是这些类的本职工作。在这种情况下,需要我们将类中存放的数值进行比较,需要进行逻辑相等的判断。除此之外的类,很大部分类没有“一个是否等于另外一个”的概念。这种不关心逻辑相等的类不需要覆盖equals方法。

超类实现的equals对子类适用

举个例子,继承了AbstractSet类的HashSet类在equals方法上并没有任何区别,那么HashSet直接使用AbstractSet的equals方法即可。

覆盖equals方法

与上面的内容相反的,我们需要覆盖equals方法的情况就是:如果类具有自己的逻辑相等的概念,并且父类没有进行可用的equals方法覆盖。这时需要我们亲自进行覆盖。

集合中equals方法的等价关系


equals方法实现了等价关系。离散数学中学习过等价关系的概念,对于一个R上的二元关系,如果它满足自反对称和传递,那么他就是等价的。我们来具体分析一下equals和这三种性质的关系。

自反性 : 对于任何非null的引用值x,x.equals(x)必须返回true

对称性 : 对于任何非null的引用值x和y,当且仅当y.equals(x)返回 true时,x.equals(y)必定返回true

传递性 : 对于任何非null的引用值x、y和z,如果x.equals(y)返回true、y.equals(z)也返回true,那么x.equals(z)必定返回true。

自反性:∀ a ∈A, => (a, a) ∈ R
对称性:(a, b) ∈R∧ a ≠ b => (b, a)∈R
传递性:(a, b)∈R,(b, c)∈R =>(a, c)∈R

对比一下这三个性质,没有任何问题。由此可得,equals方法实现了等价关系。

如何编写equals方法


Object的equals方法只是简单的看看地址,这显然不可能满足我们的要求。那么在自己编写equals方法进行覆盖时如何才能保证编写出高质量的,逻辑比较的方法呢?equals的编写可以概括为下面四步:

1.使用==操作符检查参数是否只是对象的引用
如果结果相等则返回true,说明x与y是一个对象的不同引用,不需要再进行判断了。

2.使用instanceof操作符检查参数是否类型正确
如果结果不是正确的类型则返回false,因为我们的equals方法是继承自Object类的,所以参数的类型无法避免的是Object,我们先使用instanceof对参数进行类型判断,如果类型都不正确,就不用进行下一步判断了。

3.把参数转换成正确的类型
因为之前做了检测,所以这一步的类型转换没有问题。

4.对每个类中需要逻辑比较的域值进行判断
已经确保x和y是相同类型的不同实例,将需要判断的逻辑比较的域值取出进行比较判断即可。如果全部正确则返回true,否则返回false。

关于实现的equals需要注意的问题


当编写完equals方法后,一定要反复的判断是否符合自反性,对称性和传递性。不仅仅如此,在确保等价的情况下,编写equals方法时还有一些值得注意的事情,我们需要以此改进。

覆盖equals方法时总要覆盖hashCode方法
如果我们在编写有关散列的类时,必须在覆盖equals方法时覆盖hashCode方法。因为在散列表中,逻辑相同的对象应该具有相同的散列码。举个比较简单的例子:将String存入HashSet,有可能两个内容相同的String字串用==判断为false,但是他们在HashSet中只存在了一份。这就是因为逻辑相同的String拥有这相同的hashCode。
普遍性的,如果你为你的类覆盖了equals方法,那么证明在某种情况下会有两个不同对象是逻辑相等的。此时如果与散列相关,那么这两个对象需要相同的hashCode。所以覆盖equals方法时总要覆盖hashCode方法。

不要让equals方法过于智能
如果我们只是简单的按照上面的实现流程来编写equals的方法,既符合规定也不会导致奇怪的错误。但是如果我们非要去追求各种各样、花哨的等价关系,而把代码搞得臃肿不堪,那么既违反了高内聚的初衷,也会让代码出一些莫名其妙的错误。

不要将equals方法的参数类型弄错
说出来可能感觉好笑,但这确实是会发生的情况。修改了参数类型之后的equals方法已完全于Object类没有了关系,编译器不会报错,留下的只是给程序员无尽的头痛。如果不能意识到参数类型是Object,很有可能花费几个小时也搞不清程序为什么不能正常工作。

以上是关于java覆盖equals更深层的方法概述的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
如何将Maven或Gradle用于高级Java项目管理,构建自动化和依赖性解决方案?如何将Maven或Gradle用于高级Java项目管理,构建自动化和依赖性解决方案?Mar 17, 2025 pm 05:46 PM

本文讨论了使用Maven和Gradle进行Java项目管理,构建自动化和依赖性解决方案,以比较其方法和优化策略。

如何使用适当的版本控制和依赖项管理创建和使用自定义Java库(JAR文件)?如何使用适当的版本控制和依赖项管理创建和使用自定义Java库(JAR文件)?Mar 17, 2025 pm 05:45 PM

本文使用Maven和Gradle之类的工具讨论了具有适当的版本控制和依赖关系管理的自定义Java库(JAR文件)的创建和使用。

如何使用咖啡因或Guava Cache等库在Java应用程序中实现多层缓存?如何使用咖啡因或Guava Cache等库在Java应用程序中实现多层缓存?Mar 17, 2025 pm 05:44 PM

本文讨论了使用咖啡因和Guava缓存在Java中实施多层缓存以提高应用程序性能。它涵盖设置,集成和绩效优势,以及配置和驱逐政策管理最佳PRA

如何将JPA(Java持久性API)用于具有高级功能(例如缓存和懒惰加载)的对象相关映射?如何将JPA(Java持久性API)用于具有高级功能(例如缓存和懒惰加载)的对象相关映射?Mar 17, 2025 pm 05:43 PM

本文讨论了使用JPA进行对象相关映射,并具有高级功能,例如缓存和懒惰加载。它涵盖了设置,实体映射和优化性能的最佳实践,同时突出潜在的陷阱。[159个字符]

Java的类负载机制如何起作用,包括不同的类载荷及其委托模型?Java的类负载机制如何起作用,包括不同的类载荷及其委托模型?Mar 17, 2025 pm 05:35 PM

Java的类上载涉及使用带有引导,扩展程序和应用程序类负载器的分层系统加载,链接和初始化类。父代授权模型确保首先加载核心类别,从而影响自定义类LOA

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它们
1 个月前By尊渡假赌尊渡假赌尊渡假赌

热工具

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )专业的PHP集成开发工具

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)