java Findbugs 警告:Equals 方法不应对其参数的类型进行任何假设

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/364454/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 12:06:24  来源:igfitidea点击:

Findbugs warning: Equals method should not assume anything about the type of its argument

javaequalsfindbugs

提问by Uri

When running FindBugs on my project, I got a few instances of the error described above.

在我的项目上运行 FindBugs 时,我遇到了一些上述错误的实例。

Namely, my overriding versions of equals cast the RHS object into the same type as the object in which the overriding version is defined.

即,我的覆盖版本 equals 将 RHS 对象转换为与定义覆盖版本的对象相同的类型。

However, I'm not sure whether a better design is possible, since AFAIK Java does not allow variance in method parameters, so it is not possible to define any other type for the equals parameter.

但是,我不确定是否有更好的设计,因为 AFAIK Java 不允许方法参数发生变化,因此不可能为 equals 参数定义任何其他类型。

Am I doing something very wrong, or is FindBugs too eager?

是我做错了什么,还是 FindBugs 太急于求成?

A different way to phrase this question is: what is the correct behavior if the object passed to equals is not the same type as an LHS: Is this a false, or should there be an exception?

表述这个问题的另一种方式是:如果传递给 equals 的对象与 LHS 的类型不同,那么正确的行为是什么:这是错误的,还是应该有例外?

For example:

例如:

public boolean equals(Object rhs)
{
    MyType rhsMyType = (MyType)rhs; // Should throw exception
    if(this.field1().equals(rhsMyType.field1())... // Or whatever
}

回答by Dave L.

Typically, when implementing equals you can check to see whether the class of the argument is equal (or compatible) to the implementing class before casting it. Something like this:

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

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

Doing it this way will prevent the FindBugs warning.

这样做可以防止 FindBugs 警告。

A side note to address a comment:
Some people argue to use instanceofinstead of getClassto check type safety. There is a big debate on that, which I was trying not to get into when I noted that you can check for class equality orcompatibility, but I guess I can't escape it. It boils down to this - if you use instanceofyou can support equality between instances of a class and instances of its subclass, but you risk breaking the symmetric contract of equals. Generally I would recommend not to use instanceofunless you know you need it and you know what you are doing. For more information see:

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

回答by Joachim Sauer

You're probably doing something like this:

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

public class Foo {
  // some code

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

In this example you are assuming something about the argument of equals(): You are assuming it's of type Foo. This needs not be the case! You can also get a String (in which case you should almost definitely return false).

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

So your code should look like this:

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

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

(or use the more stringent getClass() != o.getClass()mentioned by Dave L.

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

You could also look at it this way:

你也可以这样看:

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

Is there any reason that this code should throw a ClassCastExceptioninstead of finishing normally and setting bto false?

有什么理由让这段代码应该抛出 aClassCastException而不是正常完成并设置bfalse

Throwing a ClassCastExceptionas a response to .equals()wouldn't be sensible. Because even if it is a stupid question ("Of course a String is never equal to a Foo!") it's still a valid one with a perfectly fine answer ("no" == false).

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

回答by Luzius

I'd recommend to ignore said findbugs warning. In practice, if equals is called with an object of an unexpected class, it is almost certainly a bug, and you want to fail fast on bugs.

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

For example, if you have an 'ArrayList files' and call files.contains("MyFile.txt"), it would be nice if you got a ClassCastException. Instead, Java just returns false, and it likely takes a long time until you discover that bug.

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

回答by Bombe

I start my equals(Object) implementations like this:

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

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

This will also prevent the FindBugs warning but will not automatically return falsewhen a subclass of ThisClass is being handed in. It might also be considered equal, especially if its equals(Object)method hasn't been overridden.

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