Правильно ли я реализовал equals и hashCode с помощью Google Guava? - PullRequest
10 голосов
/ 13 февраля 2012

Я использую hibernate и мне нужно переопределить equals и hashCode ().Я решил использовать помощники google-guava и 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;
    }
}

РЕДАКТИРОВАТЬ:

Нашел в наследство и получить образец здесь

Ответы [ 3 ]

18 голосов
/ 13 февраля 2012

Проблема с оператором 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.

Я знаю, что это звучит как базовые вещи, и большинство людей знают это, но чертовски легко забыть это. Теперь, если вы хотите такое поведение, тогда все в порядке, вы правильно реализовали 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;
}

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

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

12 голосов
/ 13 февраля 2012

На самом деле вы можете использовать Guava EqualsTester для проверки реализации equals и hashCode:

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

Это в тестовой библиотеке гуавы.

<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 голосов
/ 13 февраля 2012

Хорошо, как есть.Хотя instanceof делает нулевую проверку ненужной.

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

...