【问题标题】:how do I correctly override equals for inheritance in java?java - 如何在java中正确覆盖equals以进行继承?
【发布时间】:2012-04-10 18:17:30
【问题描述】:

我使用的是 hibernate 和 id... 用于持久性(这就是为什么它在比较中被省略的原因)。 (另外,使用 google guava helper equals)

HolidayPackageVariant:

public abstract class HolidayPackageVariant {
    private Integer idHolidayPackageVariant;
    private HolidayPackage holidayPackage;
    private String typeHolidayPackage;

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

    if (getClass().equals(obj.getClass())) {
        final HolidayPackageVariant otherPackageVariant = (HolidayPackageVariant) obj;
        return Objects.equal(getTypeHolidayPackage(),otherPackageVariant.getTypeHolidayPackage())
                && Objects.equal(getHolidayPackage(),
                        otherPackageVariant.getHolidayPackage());
    }
    return false;
}

@Override
public int hashCode() {
    return Objects.hashCode(getTypeHolidayPackage(), getHolidayPackage());
}

FlightHolidayPackageVariant:

public final class FlightHolidayPackageVariant extends HolidayPackageVariant{
    private Destination originCity;
    public boolean equals(Object obj) {
    // .. 

我应该完全覆盖 equals() 还是应该以某种方式调用 super.equals(...) ?

【问题讨论】:

  • getClass().equals(obj.getClass()) -> NPE 如果 obj 为空。
  • @aviad 更新了 null 检查的答案。
  • 我想知道为什么不使用 Apache Commons Lang 库中的帮助类 EqualsBuilder 和 HashCodeBuilder?
  • 刚刚发现这个问题可以很好地比较 Guava 和 Apache Commons:stackoverflow.com/questions/4542550/…

标签: java equals guava


【解决方案1】:

关注Secret of Equals

HolidayPackageVariant:

public abstract class HolidayPackageVariant {
    private Integer idHolidayPackageVariant;
    private HolidayPackage holidayPackage;
    private String typeHolidayPackage;

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

        if (getClass().equals(obj.getClass())) {
            final HolidayPackageVariant otherPackageVariant = (HolidayPackageVariant) obj;
            return Objects.equal(getTypeHolidayPackage(),otherPackageVariant.getTypeHolidayPackage())
                    && Objects.equal(getHolidayPackage(),
                            otherPackageVariant.getHolidayPackage());
        }
        return false;
    }
}

FlightHolidayPackageVariant:

public final class FlightHolidayPackageVariant extends HolidayPackageVariant{
    private Destination originCity;

    @Override
    public boolean equals(Object obj) {

        if(super.equals(obj)){
            return Objects.equal(getOriginCity(),
                    ((FlightHolidayPackageVariant)(obj)).getOriginCity());
        }
        return false;
    }
}

这将确保只有相同的类型变体彼此相等。

【讨论】:

  • FlightHolidayPackageVariant 中,if(obj==this) return true; if(obj==null) return false; 这两行完全没有必要,因为这些测试是在super.equals(obj) 中执行的第一个测试。
  • 这个链接似乎完全忽略了可替代性的问题,这很重要。作者甚至引用了 Effective Java,所以似乎她发现了 EJ 还没有发现的东西,但 EJ 已经考虑了她的解决方案并反驳了它。
  • @KevinBourrillion 你能谈谈你提到的可替代性吗?另外,请建议我在我想出的这个解决方案中进行编辑。
【解决方案2】:

这就是你应该如何实现数据对象:不允许继承,只允许组合。

这些是不可变对象,但您可能想要修改它们,因此在需要的地方删除 final。您也可以从类定义中删除 final,因为 Hibernate 不支持它,但在这种情况下,您应该记录这些类不符合继承条件。

主要优点是 Effective Java 中描述的所有优点,在这种情况下,您不必通过 Hibernate 管理继承,这有时会很痛苦。

public final class HolidayPackageVariant {
  private final Integer idHolidayPackageVariant;
  private final HolidayPackage holidayPackage;
  private final String typeHolidayPackage;

  ...

  @Override
  public boolean equals(Object obj) {
    if (obj == this)
      return true;
    if (!(obj instanceof HolidayPackageVariant))
      return false;

    HolidayPackageVariant that = (HolidayPackageVariant) obj;
    return Objects.equal(this.typeHolidayPackage, that.typeHolidayPackage)
        && Objects.equal(this.holidayPackage, that.holidayPackage);
  }

  @Override
  public int hashCode() {
    return Objects.hashCode(this.typeHolidayPackage, this.holidayPackage);
  }
}

public final class FlightHolidayPackageVariant {
  private HolidayPackageVariant holidayPackageVariant;
  private Destination originCity;

  ...

  public HolidayPackageVariant asHolidayPackageVariant() {
    return this.holidayPackageVariant;
  }

  public boolean equals(Object obj) {
    if (obj == this)
      return true;
    if (!(obj instanceof FlightHolidayPackageVariant))
      return false;

    FlightHolidayPackageVariant that = (FlightHolidayPackageVariant) obj;
    return Objects.equal(this.holidayPackageVariant, that.holidayPackageVariant)
        && Objects.equal(this.originCity, that.originCity);
  }

  @Override
  public int hashCode() {
    return Objects.hashCode(this.holidayPackageVariant, this.originCity);
  }
}

【讨论】:

  • 我一直在考虑这个问题。我想到的一个问题是,在我的 HolidayPackage 中,我存储了一个 Set<HolidayPackageVariant> variants; 来指向 HolidayPackageVariant 的具体实现,即 LandHolidayPackageVariantFlightHolidayPackageVariant。如果我将其更改为组合,那么如何在该集合中存储对 FlightHolidayPackageVariant 的引用?
  • 您真的需要将它们全部放在一个集合中吗?你不能使用几个可以在需要时使用 Guava 的Iterables.transform(Iterable, Function) 聚合的集合吗?
猜你喜欢
  • 2012-08-30
  • 1970-01-01
  • 1970-01-01
  • 2012-05-30
  • 1970-01-01
  • 2013-05-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多