24

在我的项目上运行 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
}
4

4 回答 4

48

通常,在实现 equals 时,您可以在强制转换之前检查参数的类是否与实现类相等(或兼容)。像这样的东西:

if (getClass() != obj.getClass())
    return false;
MyObj myObj = (MyObj) obj;

这样做可以防止 FindBugs 警告。

解决评论的旁注:
有些人认为使用instanceof而不是getClass检查类型安全。对此有一个很大的争论,当我注意到你可以检查类相等兼容性时,我试图不参与其中,但我想我无法逃避它。它归结为这一点 - 如果你使用instanceof你可以支持一个类的实例和它的子类的实例之间的相等性,但是你可能会破坏equals. 一般来说,我建议不要使用instanceof,除非你知道你需要它并且你知道你在做什么。有关更多信息,请参阅:

于 2008-12-12T23:10:57.997 回答
7

你可能正在做这样的事情:

public class Foo {
  // some code

  public void equals(Object o) {
    Foo other = (Foo) o;
    // the real equals code
  }
}

在本例中,您假设有关 equals() 的参数:您假设它是 Foo 类型的。不必如此!您还可以获得一个字符串(在这种情况下,您几乎肯定应该返回 false)。

所以你的代码应该是这样的:

public void equals(Object o) {
  if (!(o instanceof Foo)) {
    return false;
  }
  Foo other = (Foo) o;
  // the real equals code
}

(或使用getClass() != o.getClass()Dave L.

你也可以这样看:

Integer i = new Integer(42);
String s = "fourtytwo";
boolean b = i.equals(s);

这段代码是否有任何理由应该抛出 aClassCastException而不是正常完成并设置bfalse

抛出 aClassCastException作为回应.equals()是不明智的。因为即使这是一个愚蠢的问题(“当然,字符串永远不会等于 Foo!”)它仍然是一个有效的问题,答案非常好(“否”== false)。

于 2008-12-12T23:15:06.350 回答
2

我建议忽略上述 findbugs 警告。在实践中,如果使用意外类的对象调用 equals,几乎可以肯定它是一个错误,并且您希望在错误上快速失败。

例如,如果你有一个 'ArrayList files' 并调用 files.contains("MyFile.txt"),如果你得到一个 ClassCastException 就好了。相反,Java 只返回 false,并且您可能需要很长时间才能发现该错误。

于 2010-06-10T15:09:51.390 回答
0

我像这样开始我的 equals(Object) 实现:

if ((object == null) || !(object instaceof ThisClass)) {
    return false;
}

这也将防止 FindBugs 警告,但不会false在提交 ThisClass 的子类时自动返回。它也可能被认为是相等的,特别是如果它的equals(Object)方法没有被覆盖。

于 2008-12-12T23:17:14.740 回答