Findbugs警告:Equals方法不应该假设其参数的类型

Uri*_*Uri 19 java findbugs 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
}
Run Code Online (Sandbox Code Playgroud)

Dav*_* L. 36

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

if (getClass() != obj.getClass())
    return false;
MyObj myObj = (MyObj) obj;
Run Code Online (Sandbox Code Playgroud)

这样做会阻止FindBugs警告.

解决评论的旁注:
有些人主张使用instanceof而不是getClass检查类型安全性.关于这一点存在很大争议,当我注意到你可以检查类的相等性兼容性时,我试图不进入这个问题,但我想我无法逃脱它.它归结为这个 - 如果你使用instanceof你可以支持类的实例和它的子类的实例之间的相等,但你冒着破坏对称契约的风险equals.一般来说,我建议不要使用,instanceof除非你知道你需要它,你知道你在做什么.有关更多信息,请参阅

  • 基本上这意味着:不是抛出ClassCastException,而是equals()方法应该返回false. (4认同)
  • 尽管此代码解决了原始的FindBugs问题,但似乎导致FindBugs现在使用NP_EQUALS_SHOULD_HANDLE_NULL_ARGUMENT标记该代码。因此,您可能需要添加一个空检查,例如:if(obj2 == null || getClass()!= obj2.getClass())` (2认同)

Joa*_*uer 7

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

public class Foo {
  // some code

  public void equals(Object o) {
    Foo other = (Foo) o;
    // the real equals code
  }
}
Run Code Online (Sandbox Code Playgroud)

在这个例子中,你假设有关于equals()的参数:你假设它是Foo类型.不一定是这种情况!你也可以得到一个String(在这种情况下你几乎肯定会返回false).

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

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

(或使用getClass() != o.getClass()Dave L.提到的更严格的

你也可以这样看待它:

Integer i = new Integer(42);
String s = "fourtytwo";
boolean b = i.equals(s);
Run Code Online (Sandbox Code Playgroud)

有没有理由这个代码应该抛出ClassCastException而不是正常完成并设置bfalse

抛出一个ClassCastException回应.equals()是不明智的.因为即使它是一个愚蠢的问题("当然一个字符串永远不会等于一个Foo!")它仍然是一个有效的答案("没有"== false).