【问题标题】:Did I implement equals and hashCode correctly using Google Guava?我是否使用 Google Guava 正确实现了 equals 和 hashCode?
【发布时间】:2012-03-04 15:49:44
【问题描述】:

我正在使用休眠,需要重写 equals 和 hashCode()。我选择使用 google-guava 的 equals 和 hashCode 助手。

我想知道我是否在这里遗漏了什么。

我有 idImagefilePath 的 get/set 方法。

@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;
    }
}

编辑:

遇到继承并有一个样本here

【问题讨论】:

  • 看起来不错...您是否遇到任何错误/不需要的行为?
  • @NimChimpsky idImage 是用于在数据库中自动递增主键的 id 映射(使用休眠)。
  • @Marcelo 不,目前还没有。一切都很好。我只是想知道我是否错过了什么。
  • 对于其他任何来这里流浪的人:angelikalanger.com/Articles/JavaSolutions/SecretsOfEquals/…

标签: java equals guava hashcode


【解决方案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 运算符。

我知道这听起来像是基本的东西,大多数人都知道,但是太容易忘记它了。现在,如果你想要那种行为,那很好,你正确地实现了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 不好,不应该使用。我只是说您必须了解这种特殊情况并考虑到这一点来决定是否使用它。

【讨论】:

  • 更好——不要继承 DTO
  • en.wikipedia.org/wiki/Data_transfer_object;如果您更熟悉该术语,则大致相当于值对象。在这种情况下,您希望组合而不是继承。
  • 我认为equals 中的前两个if 语句是多余的,因为Guava 的Object#equals 就是这样做的。
  • @Sangdol equals 方法被覆盖。没有任何地方可以拨打super.equals()。这意味着Object#equals 中发生的任何事情都是无关紧要的(因为它从未执行过)。
  • 哦,我看错了你的代码。我以为你用的是 Guava 的Objects#equal。检查this code
【解决方案2】:

您实际上可以使用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());
}

【讨论】:

  • @David 不明白你的论点。
  • @David 我希望这会失败,这在这个例子中显然是正确的。
【解决方案3】:

没问题。尽管 instanceof 使 null 检查变得不必要。

另外,我认为使用自动生成的 id 很好,虽然这是 very debatable

【讨论】:

  • 我同意空检查的冗余。去掉就行了。
  • 另外,您可以继续使用getFilePath().hashCode() 而不是Objects.hashCode(getFilePath())
  • @LouisWasserman - 如果getFilePath() 可以返回null,那将会失败。文档中没有提到它,但我怀疑调用 Arrays.hashCode()Objects.hashCode() 可以安全地处理 null 值。
  • 也许,尽管getFilePath() 返回 null 可能 反映了一个错误。 ;)
猜你喜欢
  • 2013-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多