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

2022-09-01 20:03:47

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

答案 1

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

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

这样做将防止 FindBugs 警告。

解决评论的附注:
有些人主张使用而不是检查类型安全性。关于这个问题有一个很大的争论,当我注意到你可以检查阶级平等兼容性时,我试图不进入,但我想我无法逃避它。它归结为 - 如果您使用,则可以支持类的实例与其子类的实例之间的相等性,但是您可能会破坏 的对称协定。一般来说,我建议不要使用,除非你知道你需要它,你知道你在做什么。有关详细信息,请参阅:instanceofgetClassinstanceofequalsinstanceof


答案 2

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

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
}

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

你也可以这样看:

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

是否有任何理由此代码应抛出 a 而不是正常完成并设置为 ?ClassCastExceptionbfalse

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


推荐