Java equals方法的错误实现模式
我见过许多java equals()方法的实现,它们都遵循以下思路:Java equals方法的错误实现模式,java,subclass,equals,Java,Subclass,Equals,我见过许多java equals()方法的实现,它们都遵循以下思路: public boolean equals(Object other){ if (this == other) return true; //this if code if (!(other intanceof MyClass)) return false; //ends here otherMyClass = (MyClass)other;
public boolean equals(Object other){
if (this == other)
return true;
//this if code
if (!(other intanceof MyClass))
return false;
//ends here
otherMyClass = (MyClass)other;
//check all the attribute of this and otherMyClass and return true or false
//accordingly
}
if中的代码对于o1.equals(o2)(o1对象为MyClass,o2对象为MyClasss的子类)返回true,从这个意义上讲是否有问题?在大多数情况下,这不是预期的行为
不会other.getClass()!=这个.getClass()
比上面的粗体更好吗?如果(!(MyClass的其他intanceof))返回false,如果它们是不同类的实例,则返回false
我不能按照你的逻辑返回true,因为它不能返回true。但是,它可以计算为true,在这种情况下,将执行下一个语句。o.getClass()!=getClass())
违反了Liskov替换原则
引用一位伟人的话:
Liskov替换原理认为
类型还应保留其子类型,以便任何方法
因为类型应该同样适用于其子类型
《有效的Java》一书中有关于这个主题的更多细节。我认为最好的答案是@ChrisForrence(+1)的评论:
我想提醒您注意这样一个事实:使用instanceof
会使equals()
实现不对称:如果A是基类,而B扩展了A而没有定义任何其他字段或方法,那么A.equals(B)==true
但是B.equals(A)==false
其中a
是a
的实例,b
是b
的实例一年前我在一次采访中确实遇到了这个问题。我的实现也使用instanceof。我的面试官提到的关于使用getClass()==other.getClass()的两个论点突然出现在我的脑海中:
- 在任何实际情况下,您可能永远不需要子类实例等于父对象;equals方法最常用于集合(更具体地说是集合);我在实践中从未遇到过这种情况,但如果有人在这里遇到过,请随意添加任何非纯理论情况作为评论,这些情况仍然适用(老实说,我很好奇是否有这种情况)
- 记住equals合同的属性:
- 反射的
- 对称(*)
- 传递的
- 一致的
- x、 对于任何对象x,等于(null)返回false
- 在其他答案中已经指出了这一点:instanceof的对称性属性可能有问题(同样,在实践中,我很少使用包含不同类型元素的集合,但每当我有不同类型的元素时,我从一开始就知道对象实际上是不同的)
检查这个问题:但等式必须是可交换的(即如果a==b,那么b==a
),在这种情况下可能不是这样。我认为你可以忽略equals
方法的LSP…那么应该有一个专门为java equals()定义的liskov替换原则,如果一个类型的契约定义了一个等价关系,特别允许不同子类型的实例比较相等,然后,每个子类型都必须定义其equals方法来测试该等价关系,而不是其他等价关系。否则,关于LSP的任何内容都不表明必须能够创建任何特定类的实例,该类将自身报告为与任何其他对象等效,无论该对象属于同一类还是不同的类。对象的getClass()
“值”作为比较基础的合法性不亚于其他任何东西。代码中没有“return true”,因此不会。是的,你是对的:)我同意!因此,getClass()是一种方法(在系统中明确定义了对象等价的概念之后)。@Razvan,听起来getClass()
更好。尽管15年来我一直在使用instanceof
到equals()
中,但这是事实。。。但从其他情况来看,要小心。当一些类被框架广泛使用的代理包装时,这种技术可能会导致问题。