在我的项目上运行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
}
答案 0 :(得分:33)
通常,在实现equals时,您可以在强制转换之前检查参数的类是否与实现类相等(或兼容)。像这样:
if (getClass() != obj.getClass())
return false;
MyObj myObj = (MyObj) obj;
这样做会阻止FindBugs警告。
发表评论的附注:
有些人主张使用instanceof
代替getClass
来检查类型安全性。关于这一点存在很大争议,当我注意到你可以检查类相等或兼容性时,我试图不去讨论,但我想我无法逃脱它。归结为此 - 如果使用instanceof
,您可以支持类的实例与其子类的实例之间的相等性,但您可能会破坏equals
的对称契约。一般情况下,我建议您不要使用instanceof
,除非您知道自己需要它,并且知道自己在做什么。有关更多信息,请参阅:
答案 1 :(得分:7)
你可能正在做这样的事情:
public class Foo {
// some code
public void equals(Object o) {
Foo other = (Foo) o;
// the real equals code
}
}
在这个例子中,你假设有关于equals()的参数:你假设它是Foo类型。不一定是这种情况!你也可以得到一个String(在这种情况下你几乎肯定会返回false)。
所以你的代码应该是这样的:
public void equals(Object o) {
if (!(o instanceof Foo)) {
return false;
}
Foo other = (Foo) o;
// the real equals code
}
(或使用Dave L提到的更严格的getClass() != o.getClass()
。
你也可以这样看待它:
Integer i = new Integer(42);
String s = "fourtytwo";
boolean b = i.equals(s);
是否有任何理由认为此代码应该抛出ClassCastException
而不是正常完成并将b
设置为false
?
投掷ClassCastException
作为对.equals()
的回复是不明智的。因为即使这是一个愚蠢的问题(“当然一个字符串永远不会等于一个Foo!”)它仍然是一个有效的答案(“no”== false
)。
答案 2 :(得分:2)
我建议忽略所说的findbugs警告。实际上,如果使用意外类的对象调用equals,那几乎肯定是一个错误,并且你想在bug上快速失败。
例如,如果您有一个'ArrayList files'并调用files.contains(“MyFile.txt”),那么如果您遇到ClassCastException就会很好。相反,Java只返回false,并且可能需要很长时间才能发现该错误。
答案 3 :(得分:0)
我开始像这样的equals(Object)实现:
if ((object == null) || !(object instaceof ThisClass)) {
return false;
}
这也会阻止FindBugs警告,但是当提交ThisClass的子类时,它不会自动返回false
。它也可能被认为是相同的,特别是如果它的equals(Object)
方法还没有重写的。