查找错误警告:Equals 方法不应假设其参数类型的任何内容
题
在我的项目上运行 FindBugs 时,我收到了一些上述错误的实例。
也就是说,我的 equals 重写版本将 RHS 对象转换为与定义重写版本的对象相同的类型。
但是,我不确定是否可以有更好的设计,因为 AFAIK Java 不允许方法参数存在差异,因此不可能为 equals 参数定义任何其他类型。
是我做错了什么,还是 FindBugs 太急切了?
表达这个问题的另一种方式是:如果传递给 equals 的对象与 LHS 的类型不同,正确的行为是什么:这是错误的,还是应该有例外?
例如:
public boolean equals(Object rhs)
{
MyType rhsMyType = (MyType)rhs; // Should throw exception
if(this.field1().equals(rhsMyType.field1())... // Or whatever
}
解决方案
通常,在实现 equals 时,您可以在强制转换之前检查参数的类是否与实现类相等(或兼容)。像这样的东西:
if (getClass() != obj.getClass())
return false;
MyObj myObj = (MyObj) obj;
这样做可以防止 FindBugs 警告。
针对评论的旁注:
有些人主张使用 instanceof
代替 getClass
检查类型安全。对此有一个很大的争论,当我注意到你可以检查阶级平等时,我试图不参与其中 或者 兼容性,但我想我无法逃避它。归结为这一点 - 如果你使用 instanceof
您可以支持类的实例与其子类的实例之间的相等性,但是您可能会面临破坏对称契约的风险 equals
. 。一般来说我建议不要使用 instanceof
除非你知道你需要它并且你知道你在做什么。欲了解更多信息,请参阅:
- http://www.artima.com/weblogs/viewpost.jsp?thread=4744
- 在Java中重写equals和hashCode时应该考虑哪些问题?
- http://www.macchiato.com/columns/Durable5.html
- http://commons.apache.org/lang/api-release/org/apache/commons/lang/builder/EqualsBuilder.html (Apache common 的实现助手)
- http://www.eclipsezone.com/eclipse/forums/t92613.rhtml (Eclipse的默认等于生成器)
- NetBeans 生成器也使用 getClass()
其他提示
你可能做这样的事情:
public class Foo {
// some code
public void equals(Object o) {
Foo other = (Foo) o;
// the real equals code
}
}
在这个例子中我们假定你是一些有关平等的论点():你是假设它是Foo类型。这需要并非如此!您还可以得到一个String(在这种情况下,你应该几乎可以肯定返回false)。
所以,你的代码应该是这样的:
public void equals(Object o) {
if (!(o instanceof Foo)) {
return false;
}
Foo other = (Foo) o;
// the real equals code
}
(或使用由Dave大号提到的更严格的getClass() != o.getClass()
。
您还可以看看它是这样的:
Integer i = new Integer(42);
String s = "fourtytwo";
boolean b = i.equals(s);
是否有任何理由,此代码应该抛出一个ClassCastException
代替正常完成并设定b
到false
的?
投掷ClassCastException
以.equals()
的响应不会是明智的。因为哪怕是一个愚蠢的问题(“当然,一个字符串是永远等于一个Foo!”),它仍然是一个有效的具有完全没有答案(“无” == false
)。
我建议忽略说FindBugs的警告。在实践中,如果等于被称为一个意外类的一个对象,那么几乎可以肯定的错误,并且要失败的错误快。
例如,如果你有一个“ArrayList的文件”,并呼吁files.contains(“MyFile.txt的”),它会如果你有一个ClassCastException是很好的。相反,Java的只是返回false,它可能需要很长的时间,直到你发现的bug。
我开始等于(对象)实现这样的:
if ((object == null) || !(object instaceof ThisClass)) {
return false;
}
这也将防止FindBugs的警告,但是当ThisClass的一个子类中正在切换将不会自动地返回false
,它也可能被认为是相等的,特别是如果其equals(Object)
方法尚未重写。