- 浏览: 1011303 次
- 性别:
- 来自: 杭州
文章分类
- 全部博客 (826)
- 硬件 (8)
- 软件 (24)
- 软件工程 (34)
- JAVA (229)
- C/C++/C# (77)
- JavaScript (8)
- PHP (1)
- Ruby (3)
- MySQL (14)
- 数据库 (19)
- 心情记事 (12)
- 团队管理 (19)
- Hadoop (1)
- spring (22)
- mybatis(ibatis) (7)
- tomcat (16)
- velocity (0)
- 系统架构 (6)
- JMX (8)
- proxool (1)
- 开发工具 (16)
- python (10)
- JVM (27)
- servlet (5)
- JMS (26)
- ant (2)
- 设计模式 (5)
- 智力题 (2)
- 面试题收集 (1)
- 孙子兵法 (16)
- 测试 (1)
- 数据结构 (7)
- 算法 (22)
- Android (11)
- 汽车驾驶 (1)
- lucene (1)
- memcache (12)
- 技术架构 (7)
- OTP-Erlang (7)
- memcached (17)
- redis (20)
- 浏览器插件 (3)
- sqlite (3)
- Heritrix (9)
- Java线程 (1)
- scala (0)
- Mina (6)
- 汇编 (2)
- Netty (15)
- libevent (0)
- CentOS (12)
- mongod (5)
- mac os (0)
最新评论
-
kingasdfg:
你这里面存在一个错误添加多个任务 应该是这样的 /** * ...
Quartz的任务的临时启动和暂停和恢复【转】 -
kyzeng:
纠正一个错误,long型对应的符号是J,不是L。
Jni中C++和Java的参数传递 -
zhaohaolin:
抱歉,兄弟,只是留下作记录,方便学习,如果觉得资料不好,可以到 ...
netty的个人使用心得【转】 -
cccoooccooco:
谢谢!自己一直以为虚机得使用网线才可以与主机连接呢。。
主机网卡无网线连接与虚拟机通信 -
yuqilin001:
要转别人的东西,请转清楚点嘛,少了这么多类,误人子弟
netty的个人使用心得【转】
【51CTO快译】本文介绍了一种改写(override)equals 方法的技巧。使用该技巧,即使在实体类的子类添加了新的域(field)时,仍然能够满足 equals 方法的约定。
在《Effective Java》一书的第 8 条目中,Josh Bloch 将子类化时满足 equals 约定这一困难描述为:面向对象语言中等值关系的最根本问题。Bloch 这样写道:
不存在一种方式,能够在扩展非实例类并添加值组件的同时,仍然满足equals的约定。除非你愿意放弃面向对象的抽象性这一优点。
《Programming in Scala》一书中的第 28 章提供了一种方法,子类可以对非实例类进行扩展,添加值组件,而同时满足 equals 约定。虽然书中提供的那种技巧是用于定义 Scala 类,但一样适用于 Java 中的 类定义。在本文中,为了讲解这种方法,我将使用《Programming in Scala》中相关章节,改编相关的文本,并将原书中的 Scala 示例代码转换为了 Java 代码。
常见的等值陷阱
Class java.lang.Object 定义了一个 equals 方法,其中的子类可以进行改写(override)。不幸的是,最终的结果表明,在面向对象语言中,编写正确的等值方法相当困难。事实上,在对 Java 代码的大量正文进行研究之后,几位作者在 2007 年的一份论文中作出如下结论:几乎所有 equals 方法的实现都是错误的。
这是一个严重的问题,因为等值方法是很多代码的根本。其一,对于类型 C,一个错误的等值方法可能意味着,你不能可靠地将一个类型 C 的对象放入集合中。你可能有两个等值的类型 C 元素 elem1、elem2,即“em1.equals(elem2)”输出 true。然而,在下面的示例中,equals 方法的实现就是一种常见的错误:
- Set< C> hashSet = new java.util.HashSet< C>();
- hashSet.add(elem1);
- hashSet.contains(elem2); // 返回 false!
存在四种常见的陷阱,它们都会在改写equals时导致非一致性的行为:
◆使用错误的原型对equals进行定义。
◆更改equals而未同时更改 hashCode。
◆对equals进行定义时涉及可变域(field)。
◆未能成功地将equals定义为等值关系。
这四种陷阱将在下文中具体讲述。
陷阱 1:使用错误的原型对equals进行定义
在下面的代码中,我们将为普通点的类添加一个等值方法:
- public class Point {
- private final int x;
- private final int y;
- public Point( int x, int y) {
- this .x = x;
- this .y = y;
- }
- public int getX() {
- return x;
- }
- public int getY() {
- return y;
- }
- // ...
- }
一个显而易见的错误定义如下:
- // 一个完全错误的 equals 定义
- public boolean equals(Point other) {
- return ( this .getX() == other.getX() && this .getY() == other.getY());
- }
这种方法的错误之处是什么?初一看,它可以正常运行:
- Point p1 = new Point( 1 , 2 );
- Point p2 = new Point( 1 , 2 );
- Point q = new Point( 2 , 3 );
- System.out.println(p1.equals(p2)); // prints true
- System.out.println(p1.equals(q)); // 输出 false
然而,一旦你将point放入集合中,问题就出来了:
- import java.util.HashSet;
- HashSet< Point> coll = new HashSet< Point>();
- coll.add(p1);
- System.out.println(coll.contains(p2)); // 输出 false
coll 怎么可能不包含 p2 呢?你已经将 p1 添加到其中,而 p1 等于 p2。在下面的互操作中,进行比较的点的具体类型被隐藏,这时,导致问题的原因将清晰可见。将 p2a 定义为 p2 的别名,但使用的是 Object 类型而不是 Point:
- Object p2a = p2;
现在,如果你重复第一个比较,使用别名 p2a 而不是 p2,结果是:
- System.out.println(p1.equals(p2a)); // 输出 false
哪里出错了呢?事实上,由于类型不同,之前指定的 equals 版本并没有改写标准方法 equals。下面是在根类 Object 中定义的 equals 方法:
- public boolean equals(Object other)
由于 Point 中的 equals 方法使用 Point 而不是 Object 作为参数,因此,它并未对 Object 中的 equals 进行改写。相反,它只是一种重载的替代方法。Java 中重载由参数的静态类型解析,而不是运行时(run-time)类型。因此,只要参数的静态类型是 Point,就调用 Point 中的 equals 方法。同样,如果静态参数是 Object 类型,就调用 Object 中的 equals 方法。该方法没有被改写,因此在对 object 参数进行比较时,仍使用该方法。这就是“p1.equals(p2a)”输出 false 的原因,即使点 p1 和 p2a 具有相同的 x 和 y 值。这也是为什么在 HashSet 中 contains 方法返回 false 的原因。该方法是针对对常规集合进行操作,因此它会调用 Object 中的常规 equals 方法,而不是 Point 中重载的方法变种。
下面的代码定义了一个更好的equals方法:
- // 一个更好的定义,但仍不是完美的
- @Override public boolean equals(Object other) {
- boolean result = false ;
- if (other instanceof Point) {
- Point that = (Point) other;
- result = ( this .getX() == that.getX() && this .getY() == that.getY());
- }
- return result;
- }
现在,equals 具有了正确的类型。它将 Object 类型的值作为参数并输出一个 boolean 结果。该方法的实现使用了 instanceof 和 cast(类型转换)。它首先检测其他(other)对象是否为 Point 类型。如果是,它将对这 2 个点的坐标进行比较,然后返回结果。否则,输出为 false。
陷阱2 :更改equals而未同时更改hashCode
如果你使用 Point 的最新定义,再次对 p1和 p2a 进行比较,将会得到期望中的结果:true。但是,如果你重复 HashSet.contains 测试,结果仍可能是 false:
- Point p1 = new Point( 1 , 2 );
- Point p2 = new Point( 1 , 2 );
- HashSet< Point> coll = new HashSet< Point>();
- coll.add(p1);
- System.out.println(coll.contains(p2)); // (很可能)输出 false
事实上,输出结果不是百分百确定。你也可能从测试中得到true值。如果得到的结果是true,你可以试试另外一些坐标为1和2的点。最终,你将会找到一个未包含在集合中的点。这里出现错误的原因是,Point重定义了equals而没有对hashCode进行重定义。
请注意,上述实例中的集合为HashSet。这表示,集合中元素被放在由相应的散列码决定的哈希桶(hash bucket)中。在contains测试中,它首先查找散列桶,然后对哈希桶中的所有元素和指定元素进行比较。现在,Point类的最新版本确实对 equals进行了重定义,但它没有同时对hashCode进行重定义。所以 hashCode 仍然保持 Object 类中其版本的值:分配对象地址的某种变化格式。p1 和 p2 的散列码几乎肯定是不同,即使这两个点的域(field)是相同的。不同的散列码意味着集合中散列桶具有较高概率的非重复性。contains 测试将根据 p2 的散列码在相应的散列桶中查找匹配的元素。大多数情况下,点 p1 会位于另一个散列桶中,因此绝不会找到它。p1 和 p2 有可能很偶然地位于同一散列桶中。对于这种情况,测试将返回ture 值。
问题在于,Point 的上次实现违法了Object 类中定义的hashCode约定:
如果两个对象根据equals(Object) 方法是等值的,那么对两个对象中任何一个调用 hashCode 方法都必须得到相同的整型结果。
事实上,在Java中,通常应同时对 hashCode 和equals进行重定义,这一事实是广为人知的。此外,hashCode 可能仅依赖equals所依赖的域。对于 Point 类,以下将是一个合适的 hashCode 定义:
- public class Point {
- private final int x;
- private final int y;
- public Point( int x, int y) {
- this .x = x;
- this .y = y;
- }
- public int getX() {
- return x;
- }
- public int getY() {
- return y;
- }
- @Override public boolean equals(Object other) {
- boolean result = false ;
- if (other instanceof Point) {
- Point that = (Point) other;
- result = ( this .getX() == that.getX() && this .getY() == that.getY());
- }
- return result;
- }
- @Override public int hashCode() {
- return ( 41 * ( 41 + getX()) + getY());
- }
- }
这只是 hashCode 多种可能的实现中的一种。将常量 41 加到一个整型域 x 上,所得结果再乘以素数 41,然后在加上另一个整型域 y。这样就可以提供合理分布的散列码,而运行时间和代码大小也会降低。
在定义与 Point 相似的类时,添加 hashCode 解决了等值的问题。但是,还有其他的问题需要注意。
陷阱 3 :对equals进行定义时涉及可变域
以下对 Point 类进行一项细微的修改:
- public class Point {
- private int x;
- private int y;
- public Point( int x, int y) {
- this .x = x;
- this .y = y;
- }
- public int getX() {
- return x;
- }
- public int getY() {
- return y;
- }
- public void setX( int x) {
- this .x = x;
- }
- public void setY( int y) {
- this .y = y;
- }
- @Override public boolean equals(Object other) {
- boolean result = false ;
- if (other instanceof Point) {
- Point that = (Point) other;
- result = ( this .getX() == that.getX() && this .getY() == that.getY());
- }
- return result;
- }
- @Override public int hashCode() {
- return ( 41 * ( 41 + getX()) + getY());
- }
- }
唯一的不同之处是域 x 和 y 不再是 final 类型,同时添加了两个集合方法,允许用户更改 x 和 y 值。现在,equals和 hashCode 方法的定义涉及了这些可变域,因此域更改时它们的结果也将改变。一旦你将点放入集合中,这会带来很奇怪的效果:
- Point p = new Point( 1 , 2 );
- HashSet< Point> coll = new HashSet< Point>();
- coll.add(p);
- System.out.println(coll.contains(p)); // 输出 true
现在,如果更改点 p 中的域,集合还将包含该点吗? 我们来试试下面的代码:
- p.setX(p.getX() + 1 );
- System.out.println(coll.contains(p)); // (很可能)输出 false
这看起来很奇怪。p 到哪里去了?如果你对集合的 iterator 是否包含 p 进行测试,会得到各位奇怪的结果:
- Iterator< Point> it = coll.iterator();
- boolean containedP = false ;
- while (it.hasNext()) {
- Point nextP = it.next();
- if (nextP.equals(p)) {
- containedP = true ;
- break ;
- }
- }
- System.out.println(containedP); // 输出 true
此处的集合不包含 p,但 p 却在该集合的元素之中!发生了什么事呢?在更改 x 域之后,点 p 最后被放在了该集合 coll 下错误的散列桶中。也就是,其初始散列桶与散列码的新值已不再对应。在某种意义上可以说,点 p 在集合 coll 中消失了,即使它仍然是集合中元素。
从这个示例得出的教训就是,当equals和 hashCode 取决于可变状态时,可能会为用户带来问题。如果他们将这种对象放入集合中,必须小心,不要修改决定性的状态。而这是很棘手的。如果你现在需要进行一个比 较,要考虑到对象的当前状态,通常不应直接使用 equals,而是使用其他命名。 对于 Point 的上一个定义,更为可取的是省略 hashCode 的重定义,并且命名比较方法 equalContents,或者使用其他不同于equals的命名。 这样,Point 将能够继承equals和 hashCode 的缺省实现。
陷阱 4:未能成功地将equals定义为等值关系
Object 中equals的约定指出 equals 必须实现非空对象的等值关系:
◆自反性 :对于如何非空值 x,表达式 x.equals(x) 应返回true。
◆对称性 :对于任何非空值:x 和 y,x.equals(y) 应返回true,当且仅当 y.equals(x) 返回 true。
◆传递性 :对于任何非空值 x、y、z,如果 x.equals(y)返回 true 并且 y.equals(z) 返回 true,那么x.equals(z) 应返回 true。
◆一致性 :对于任何非空值:x 和 y,多次调用 x.equals(y)应始终返回 true 或始终返回 false,如果对象的equals比较中所用信息未被修改。
◆对于任何非空值 x,x.equals(null) 应返回 false。
目前,对于 Point 类所使用的equals定义满足了equals的约定。然而,一旦涉及子类,事情将变得更加复杂。比如说,Point 有一个子类 ColoredPoint,其中添加了一个 Color 类型的域 color。假定将 Color 定义为枚举类型:
- public enum Color {
- RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET;
- }
ColoredPoint 改写 equals,并添加新的 color 域:
- public class ColoredPoint extends Point { // 问题:equals 不对称
- 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;
- }
- }
很多程序员都可能这样编写代码。请注意,在这种情况下,类 ColoredPoint 不必改写 hashCode。因为 ColoredPoint 的equals的新定义比 Point 中被改写的定义更为严格(意味着等值的对象更少),hashCode 的约定仍然有效。 如果两个颜色点是相等的,它们必须具有相同的坐标,因此也已保证它们的散列码是相等的。
以类 ColoredPoint 本身为例,equals的定义看起来没问题。但,一旦普通点和颜色点混合着一起时,equals的约定就将被破坏。 例如:
- Point p = new Point( 1 , 2 );
- ColoredPoint cp = new ColoredPoint( 1 , 2 , Color.RED);
- System.out.println(p.equals(cp)); // 输出 true
- System.out.println(cp.equals(p)); // 输出 false
相等比较“pequalscp”将调用 p 的equals方法,已在类 Point 中定义。该方法仅考虑两个点的坐标。因此,相等比较输出 true 值。而另一方面,相等比较“cp equals p”调用 cp 的 equals 方法,其中类 ColoredPoint 中已定义。该方法返回 false,因为 p 不是 ColoredPoint。该方法返回 false,因为 p 不是 ColoredPoint。 因此,equals定义的关系不是对称的。
对称的缺失将为集合造成意想不到的后果。下面为一个示例:
- Set< Point> hashSet1 = new java.util.HashSet< Point>();
- hashSet1.add(p);
- System.out.println(hashSet1.contains(cp)); // 输出 false
- Set< Point> hashSet2 = new java.util.HashSet< Point>();
- hashSet2.add(cp);
- System.out.println(hashSet2.contains(p)); // 输出 true
因此,即使 p 和 cp 是相等的,一个 contains 测试成功,而另一个却失败。
如何更改equals的 定义可以让它变为对称?基本上有两种方式。您可以使关系更一般或更严格。使它更加一般意味着对两个对象,a 和 b 被认为是相等的,如果比较 a 和 b 或 b 和 a 输出 true。以下为完成该功能的代码:
- public class ColoredPoint extends Point { // 有问题:equals 不具有传递性
- 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));
- }
- else if (other instanceof Point) {
- Point that = (Point) other;
- result = that.equals( this );
- }
- return result;
- }
- }
在 ColoredPoint 中,equals的新定义比旧版本多了一种情况的检查:如果其他对象是 Point 而不是 ColoredPoint,该方法将使用 Point 的equals方法。这样就可以取得预期的效果,使equals具有对称性。现在,“cp.equals(p)”和“p.equals(cp)”都返回 true。 然而,equals的约定还是被打破了。现在的问题是,新的关系不再具有传递性!为了演示这个问题,下面进行一系列的声明。定义一个点和两个不同色的颜色 点,所有点在同一位置:
- ColoredPoint redP = new ColoredPoint( 1 , 2 , Color.RED);
- ColoredPoint blueP = new ColoredPoint( 1 , 2 , Color.BLUE);
单独来看,redp 等于 p 并且 p 等于 bluep:
- System.out.println(redP.equals(p)); // 输出 true
- System.out.println(p.equals(blueP)); // 输出 true
然而,比较 redP 和 blueP,输出 false:
- System.out.println(redP.equals(blueP)); // 输出 false
因此,这违反了equals约定中的传递性子条款。
让equals关系更一般看来是死路一条。下面我们试试让它更严格。使equals更严格的一个方法是:不同类的对象,不同地对待。通过修改类 Point 和 ColoredPoint 中的equals方法来实现。 在类 Point 中,可以添加一个额外的比较,用于检查其他点的运行时类是否与这个点的类相同,代码如下:
- // 技术上有效,但仍不能令人满意的 equals 方法
- public class Point {
- private final int x;
- private final int y;
- public Point( int x, int y) {
- this .x = x;
- this .y = y;
- }
- public int getX() {
- return x;
- }
- public int getY() {
- return y;
- }
- @Override public boolean equals(Object other) {
- boolean result = false ;
- if (other instanceof Point) {
- Point that = (Point) other;
- result = ( this .getX() == that.getX() && this .getY() == that.getY()
- && this .getClass().equals(that.getClass()));
- }
- return result;
- }
- @Override public int hashCode() {
- return ( 41 * ( 41 + getX()) + getY());
- }
- }
然后,你就可以将类 ColoredPoint 的实现恢复为之前违反了对称性要求的版本:
- 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 的实例被认为与系统类的其他实例是相等的,仅当对象具有相同的坐标,并且具有相同的运行时类,即每个对象 .getClass() 返回相同的值。 新的定义可以满足对象性和传递性的要求,因为现在对不同类之间的每次对比都将返回 false。因此,颜色点永远不会与普通点相等。这种约定看起来是合理的,当有人会指出新的定义太过严格了。
下面使用稍微有点绕的方式定义位于坐标(1, 2)上的点:
- Point pAnon = new Point( 1 , 1 ) {
- @Override public int getY() {
- return 2 ;
- }
- };
pAnon 等于 p 吗?答案是否定的,因为与 p 和 pAnon 关联的 java.lang.Class 对象是不同的。对于 p 是 Point 类,而对于 pAnon,它是 Point 的一个匿名子类。 但显然,pAnon 只是位于坐标(1, 2)上的另一个点。 认为它与 p 不同,看起来并不合理。
明智的方式:canEqual 方法
从以上各种情况,看起来我们进退两难。是否存在一种明智的方式,在类层次结构的多个分层中对等值比较进行重定义,而同时满足其约定?事实上,有这样 一种方式,但它需要另一个方法来重定义equals和 hashCode。这个想法是,只要类重定义 equals(和 hashCode),它就应该同时显式地声明,该类的所有对象与使用不同等值方法的超类中的对象,绝对不会相等。通过对重定义equals的每个类添加方 法 canEqual 就可以实现。以下为该方法的原型:
- public boolean canEqual(Object other)
当其他(other)对象是(重)定义了 canEqual 的类的实例时,该方法应返回 true,或者返回 false。它从equals中调用,以确保这些对象使用2种方式都是可比较的。下面是类 Point 新的也是最后的一个实现:
- public class Point {
- private final int x;
- private final int y;
- public Point( int x, int y) {
- this .x = x;
- this .y = y;
- }
- public int getX() {
- return x;
- }
- public int getY() {
- return y;
- }
- @Override public boolean equals(Object other) {
- boolean result = false ;
- if (other instanceof Point) {
- Point that = (Point) other;
- result = (that.canEqual( this ) && this .getX() == that.getX() && this .getY() == that.getY());
- }
- return
发表评论
-
调试jdk中的源码,查看jdk局部变量
2013-06-15 23:30 1048调试jdk中的源码,查看jdk局部变量 2012-04 ... -
Eclipse快捷键 10个最有用的快捷键<转>
2013-04-11 23:28 1070Eclipse中10个最有用的快捷键组合 一个Eclip ... -
Lucene 3.6 中文分词、分页查询、高亮显示等
2012-12-09 23:35 18101、准备工作 下载lucene 3.6.1 : htt ... -
Maven实战(九)——打包的技巧(转)
2012-10-12 00:41 932“打包“这个词听起 ... -
基于Maven的web工程如何配置嵌入式Jetty Server开发调试环境(转)
2012-10-12 00:28 9161、首先在web工程的POM文件里添加依赖jar包如下: ... -
轻轻松松学Solr(1)--概述及安装[转]
2012-09-18 14:59 990概述 这段时间对企 ... -
分析Netty工作流程[转]
2012-09-04 19:02 883下面以Netty中Echo的例 ... -
让eclipse在ubuntu下面好看一点
2012-03-27 10:17 914<p> </p> <h1 cla ... -
zookeeper安装和应用场合(名字,配置,锁,队列,集群管理)[转]
2012-01-12 17:59 1647安装和配置详解 本文 ... -
Jakarta-Common-BeanUtils使用笔记[转]
2012-01-10 14:13 1153Jakarta-Common-BeanUtils ... -
一个关于Java Thread wait(),notify()的实用例【转】
2012-01-07 16:05 1019///// // ProducerConsume ... -
Java基础:Java中的 assert 关键字解析【转】
2012-01-06 19:50 1056J2SE 1.4在语言上提供了 ... -
一篇不错的讲解Java异常的文章(转载)----感觉很不错,读了以后很有启发[转]
2012-01-06 15:02 1259六种异常处理的陋习 ... -
如何解决HP QC(Quality Center)在Windows 7下不能工作的问题
2011-12-26 10:48 1574HP QC(Quantity Center) 是一款不错的测 ... -
JAVA读写文件,中文乱码 【转】
2011-12-19 23:43 2115最近在做HTML静态生成,需要从硬盘上把模版文件的内容读出来。 ... -
Java 6 JVM参数选项大全(中文版)【转】
2011-12-19 19:51 966Java 6 JVM参数选项大全(中文版) 作者 ... -
使用assembly plugin实现自定义打包【转】
2011-12-13 01:58 965在上一篇文章中,讨论到在对maven的机制不熟悉的情况下,为了 ... -
使用maven ant task实现非标准打包[转]
2011-12-13 01:56 1045maven很强大,但是总有些事情干起来不是得心应手,没有使用a ... -
Java日期转换SimpleDateFormat格式大全【转】
2011-12-08 20:22 130924小时制时间 显示: public clas ... -
使用Spring的表单标签库
2011-11-22 20:08 106713.9. 使用Spring的 ...
相关推荐
在Java编程中,正确实现`equals`方法至关重要,它不仅影响对象的比较逻辑,还直接关系到集合类(如`HashSet`、`HashMap`等)的行为。本文将深入探讨Java中`equals`方法的一些常见陷阱,并提供相应的解决方案。 ####...
在Java编程语言中,`hashCode()`和`equals()`方法是非常重要的概念,它们不仅对于深入理解Java内存管理至关重要,也是实现自定义类的关键部分之一。本文将详细介绍这两个方法的工作原理、使用场景以及它们之间的关系...
`equals`方法是`Object`类的一个成员方法,用于比较两个对象的内容是否相等。默认情况下,`equals`方法的行为与`==`类似,即比较的是对象的引用。然而,在许多情况下,特别是对于自定义类或Java标准类库中的类(如`...
事实上,研究表明,几乎所有的equals方法的实现都是错误的!这个问题是因为等价是和很多其他的事物相关联。例如,一个类型C的错误等价方法可能意味着你无法将这个类型C的对象可信赖的放入到容器中。 equals方法的...
而`equals()`方法是Object类中的一个成员方法,它的默认行为也是比较两个对象的引用是否相等,与`==`一致。但是,很多类(如String、Integer等)都重写了`equals()`方法,以便进行更深层次的内容比较。例如,String...
Java 中的 equals 方法是一种用于比较对象是否相等的方法,它是 Object 类中的一个方法。然而,重写 equals 方法并不是一件简单的事情,因为它需要遵守一些约定,否则可能会出现一些不可预期的行为。在这篇文章中,...
1. Object类的所有方法及功能:Object类是Java中的顶层类,所有类实际上都继承了Object类的所有方法。Object类提供了以下方法: * protected Object clone():用于获得此对象的一个拷贝 * public Boolean equals...
在Java编程语言中,`equals()` 和 `hashCode()` 方法是Object类中定义的基本方法,所有类都默认继承自Object类,因此每个Java对象都有这两个方法。这两个方法在处理集合类,尤其是Set接口的实现(如HashSet)时起着...
在Java编程语言中,`equals()` 和 `hashCode()` 方法是Object类中的两个核心方法,所有类都默认继承自Object类。这两个方法在处理对象比较和集合操作时起着至关重要的作用。当我们创建自定义类并需要对对象进行精确...
equals 方法是用于比较两个对象是否相同的。它的默认实现是比较两个对象的引用是否相同,如果是同一个对象,那么 equals 方法将返回 true,否则返回 false。但是,如果我们想要比较两个对象的实际内容是否相同,那么...
在Java编程语言中,`hashCode()`和`equals()`方法是非常重要的概念,它们主要用于处理对象的唯一标识和对象之间的相等性判断。正确地实现这两个方法对于确保程序的高效运行至关重要。 #### `hashCode()`方法解析 `...
在Java编程语言中,`equals()` 方法是一个关键的成员函数,它主要用于比较对象的值是否相等。这个方法源自于 `Object` 类,是所有其他类的基类。默认情况下,`equals()` 方法的行为与 `==` 运算符相同,即比较两个...
- 接口只定义方法签名,不允许有方法实现(Java 8后可以有默认方法),支持多继承。 - 抽象类可以有方法实现,只能单继承,提供部分实现,作为子类的基础。 9. **变量类型**: - 成员变量属于类,存在于堆内存,...
然而,在Java中,并非所有的方法都可以被覆盖,特别是静态方法。 **1.1 方法覆盖的概念** 方法覆盖是指子类重写父类中的方法,以便提供不同的实现细节。在Java中,只有实例方法可以被覆盖,而静态方法则不行。这是...
总之,理解并正确实现`equals()`和`hashCode()`方法是Java编程中的基础技能,特别是在设计和使用自定义对象时,这关系到对象的正确比较和哈希表的高效操作。遵循Java的约定并确保这两个方法的一致性,可以确保代码的...
此外,正确实现equals和hashCode方法对于满足Java集合框架的期望至关重要。 9. **转换异常处理**:将字符串转换为数字时,应处理可能的NumberFormatException,确保代码在遇到无效输入时能优雅地处理。 10. **日志...
equals() 方法是 Java 中的一个方法,它用于比较两个对象的内容是否相等。equals() 方法是 Object 类中的一个方法,该方法的初始行为是比较对象的内存地址,但是可以被子类重写以比较对象的成员变量值是否相同。 ...
首先,`equals()`方法是`java.lang.Object`类的一个成员方法。它的默认实现是基于对象的引用比较,也就是说,它会检查两个对象在内存中的地址是否相同,这与`==`运算符的行为一致。然而,许多类,特别是像`String`...
在Java编程中,`equals`方法是用于比较两个对象是否相等的重要方法。通常,`equals`方法在类中被重写以实现特定的比较逻辑,因为默认的`equals`行为(即`Object`类中的实现)仅仅基于引用的相等性,即比较两个对象...