Может ли что-нибудь предупредить меня против type.equals(несовместимыйТип)?

Есть ли какой-нибудь инструмент, который может предупредить меня о следующем виде кода:

if ( someClass.equals( someString ))

Например:

if ( myObject.getClass().equals( myClassName ))

Такая вещь является юридической Java (equals принимает объект), но никогда не будет оценивать значение true (класс никогда не может равняться String), поэтому почти наверняка ошибка.

Я проверил Eclipse, FindBugs и PMD, но никто не поддерживает эту функцию?

Ответ 1

Да, IntelliJ IDEA имеет такую ​​проверку, которая, по моему мнению, включена по умолчанию. Он содержит следующие флаги:

Class<?> clazz = String.class;
if (clazz.equals("foo")) {
   //...
}

С предупреждением:

'равно()' между объектами необратимых типов.

Инспекцию можно включить/отключить с помощью "Настройки" - "Настройки проекта" → "Инспекции", затем "Вероятные ошибки" установите/снимите флажок "" равно() между объектами неконвертируемых типов.

FindBugs также должен поймать это с помощью "EC: Вызов для equals() для сравнения разных типов" Проверка ошибок, Он может быть интегрирован с Eclipse, как вам кажется, вы знаете.

Тем не менее, это не серебряная пуля; они не могут читать ваши мысли. Лучшее, на что вы можете надеяться, это то, что оно будет способствовать ложным срабатываниям, а не ложным негативам.

Ответ 2

То, что вы проверяете, не обязательно является "проблемой": equals() объявляется в классе Object и принимает и Object как его параметр. Классы переопределяют этот метод, и их реализация вполне может позволить объекту другого класса "равным" целевому объекту.

Я сделал это несколько раз сам, например, для того, чтобы позволить объекту "равный" другому объекту, если другой объект (скажем, String) соответствует ключевому полю цели:

class MyClass {
    private String id;

    public boolean equals(Object obj) {
        // Compare as if "this" is the id field
        return id.equals(obj instanceof MyClass ? ((MyClass)obj).id : obj);
    }

    public int hashCode() {
        return id.hashCode(); // so hashCode() agrees with equals()
    }
}

Это действительно очень удобно, потому что следующий код будет работать по желанию:

List<MyClass> list = new ArrayList<MyClass>();
// collection methods will work with instances:
list.contains(someInstance);
list.remove(someInstance);
list.indexOf(someInstance);
// and with keys!
// handy if you can only get the key, for example from a web url parameter
list.contains("somekey");
list.remove("somekey");
list.indexOf("somekey");

Ответ 3

Это идея интерфейса IEquatable<T> в .NET: предоставление механизма для типов для реализации того, что я назову строго типизированным равенством. Существует также интерфейс IEqualityComparer<T>, позволяющий реализовать эту логику в отдельном типе.

В соответствии с fooobar.com/info/282861/... (ответил Джон Скит, который, как правило, знает, о чем он говорит), похоже, что в Java нет эквивалента.

Конечно, вы всегда можете реализовать такую ​​вещь самостоятельно для своих типов, но это не принесет вам много пользы от типов, которые являются частью библиотек базового класса Java. Для обнаружения таких проблем во время компиляции лучшим вариантом является какой-то инструмент анализа (Mark Peters указывает, что есть, по-видимому, один встроенный в IntelliJ IDEA), который может предложить вы, что определенный код может быть подозрительным. В общем, если вы не игнорируете предупреждения, это должно быть достаточно хорошим.