Предупреждение об ошибках:Метод Equals не должен ничего предполагать о типе своего аргумента.

StackOverflow https://stackoverflow.com/questions/364454

  •  21-08-2019
  •  | 
  •  

Вопрос

При запуске FindBugs в моем проекте я несколько раз получал описанную выше ошибку.

А именно, мои переопределяющие версии равенства приводят объект RHS к тому же типу, что и объект, в котором определена переопределяющая версия.

Однако я не уверен, возможен ли лучший дизайн, поскольку AFAIK Java не допускает различий в параметрах метода, поэтому невозможно определить какой-либо другой тип для параметра равенства.

Я делаю что-то очень неправильно, или FindBugs слишком нетерпелив?

Другой способ сформулировать этот вопрос:каково правильное поведение, если объект, переданный в Equals, не того же типа, что и LHS:Это неверно или должно быть исключение?

Например:

public boolean equals(Object rhs)
{
    MyType rhsMyType = (MyType)rhs; // Should throw exception
    if(this.field1().equals(rhsMyType.field1())... // Or whatever
}
Это было полезно?

Решение

Обычно при реализации равенства вы можете проверить, равен ли (или совместим) класс аргумента реализующему классу, прежде чем приводить его.Что-то вроде этого:

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

Если вы сделаете это таким образом, вы предотвратите появление предупреждения FindBugs.

Примечание к комментарию:
Некоторые люди утверждают, что следует использовать instanceof вместо getClass для проверки безопасности типов.По этому поводу идет большая дискуссия, в которую я старался не вдаваться, когда заметил, что вы можете проверить равенство классов. или совместимость, но я думаю, я не могу избежать этого.Это сводится к следующему: если вы используете instanceof вы можете поддерживать равенство между экземплярами класса и экземплярами его подкласса, но вы рискуете нарушить симметричный контракт equals.Вообще я бы рекомендовал не использовать instanceof если только вы не знаете, что вам это нужно, и не знаете, что делаете.Для получения дополнительной информации см.:

Другие советы

Вероятно, вы делаете что-то вроде этого:

public class Foo {
  // some code

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

В этом примере вы предполагаете что-то относительно аргумента методаquals():Вы предполагаете, что это тип Foo.Этого не должно быть!Вы также можете получить строку (в этом случае вы почти наверняка должны вернуть false).

Итак, ваш код должен выглядеть так:

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

(или используйте более строгий getClass() != o.getClass() упомянутый Дэйвом Л.

Вы также можете посмотреть на это так:

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

Есть ли какая-либо причина, по которой этот код должен выдавать ошибку ClassCastException вместо того, чтобы нормально закончить и установить b к false?

Бросать ClassCastException как ответ на .equals() было бы неразумно.Потому что даже если это глупый вопрос («Конечно, строка никогда не равна Foo!»), он все равно правильный и имеет прекрасный ответ («нет» == false).

Я бы рекомендовал игнорировать указанное предупреждение findbugs.На практике, если метод Equals вызывается с объектом неожиданного класса, это почти наверняка ошибка, и вы хотите быстро устранить ошибки.

Например, если у вас есть «Файлы ArrayList» и вы вызываете files.contains («MyFile.txt»), было бы неплохо, если бы вы получили исключение ClassCastException.Вместо этого Java просто возвращает false, и, вероятно, пройдет много времени, прежде чем вы обнаружите эту ошибку.

Я начинаю свои реализации равенства (Объекта) следующим образом:

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

Это также предотвратит появление предупреждения FindBugs, но не приведет к автоматическому возврату. false когда передается подкласс ThisClass.Его также можно было бы считать равным, особенно если equals(Object) метод не был переопределен.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top