Я правильно использовал equals и hashCode с помощью Google Guava?

Я использую hibernate и мне нужно переопределить equals и hashCode(). Я решил использовать помощники google-guava equals и hashCode.

Я хотел знать, не хватает ли здесь чего-то здесь.

У меня есть методы get/set для idImage и filePath.

@Entity
@Table(name = "IMAGE")
public class ImageEntity {
    private Integer idImage;
    private String filePath;

    @Override
    public int hashCode() {
        return Objects.hashCode(getFilePath());
    }

    @Override
    public boolean equals(final Object obj) {
        if(obj == this) return true;
        if(obj == null) return false;

        if(obj instanceof ImageEntity){
            final ImageEntity otherImage = (ImageEntity) obj;
            return Objects.equal(getFilePath(), otherImage.getFilePath());
        }
        return false;
    }
}

EDIT:

Перейдите в наследование и введите образец здесь

Ответ 1

Проблема с оператором instanceof заключается в том, что он работает с учетом полиморфизма, если можно так выразиться.

Скажем, например, что вы это делаете:

public class AdvancedImageEntity extends ImageEntity
{
    //some code here
}

а затем вы выполните следующее:

ImageEntity ie = new ImageEntity ();
AdvancedImageEntity advanced_ie = new AdvancedImageEntity ();

boolean this_will_be_true = ie.equals (advanced_ie);

Как следует из названия, вызов equals возвращает true из-за оператора instanceof.

Я знаю, это звучит как базовый материал, и большинство людей это знает, но SOOOO проклятие легко забыть. Теперь, если вы хотите этого поведения, то это прекрасно, вы внедрили equals правильно. Но если вы считаете, что объект ImageEntity не должен быть равен (гипотетическому) объекту AdvancedImageEntity, то либо объявить ImageEntity равным final, либо забыть о instanceof и реализовать ваш метод equals, как этот

@Override public boolean equals(final Object obj)
{
    if(obj == this) return true;
    if(obj == null) return false;

    if (getClass ().equals (obj.getClass ()))
    {
        final ImageEntity otherImage = (ImageEntity) obj;

        return Object.equals (getFilePath(), otherImage.getFilePath());
    }

    return false;
}

Это проверит тип объекта true, независимо от типа ссылки. Если параметр obj является экземпляром подкласса, он "проскальзывает" на instanceof. Но getClass гораздо более строгий и не позволит этого.

PS: Я не говорю, что instanceof плохой и не должен использоваться. Я просто говорю, что вы должны знать об этой конкретной ситуации и решить, следует ли использовать ее с учетом этого.

Ответ 2

Фактически вы можете использовать Guava EqualsTester, чтобы проверить реализацию equals и hashCode:

new EqualsTester()
     .addEqualityGroup("hello", "h" + "ello")
     .addEqualityGroup("world", "wor" + "ld")
     .addEqualityGroup(2, 1 + 1)
     .testEquals();

Это в тестовом листе guava.

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava-testlib</artifactId>
    <scope>test</scope>
</dependency>

Незначительное изменение вашей реализации:

@Override public boolean equals(final Object obj) {
    if(obj == this) return true;
    return obj instanceof ImageEntity &&
        Objects.equal(getFilePath(), ((ImageEntity) obj).getFilePath());
}

Ответ 3

Его штраф как есть. Хотя instanceof делает нулевую проверку неочевидной.

Кроме того, я считаю, что это прекрасно использовать автоматически сгенерированные идентификаторы, хотя это очень дискуссионный.