Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/391.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
基类和子类中的Java-equals方法_Java_Equals - Fatal编程技术网

基类和子类中的Java-equals方法

基类和子类中的Java-equals方法,java,equals,Java,Equals,我有一个简单的基类,后来被许多单独的类扩展,这些类可能引入新的字段,但不一定。我在基类中定义了一个equals方法,但也为一些子类重写了它。在基类/子类中混合定义可以吗?在我的例子中,它是为了避免代码重复检查相同的字段。我认为只要您遵循和约定就可以了。您可以使用super()方法调用您正在扩展的类的方法,以防止任何代码重复的需要 public class BaseClass { public boolean equals(BaseClass other) { return (othe

我有一个简单的基类,后来被许多单独的类扩展,这些类可能引入新的字段,但不一定。我在基类中定义了一个equals方法,但也为一些子类重写了它。在基类/子类中混合定义可以吗?在我的例子中,它是为了避免代码重复检查相同的字段。

我认为只要您遵循和约定就可以了。

您可以使用
super()
方法调用您正在扩展的类的方法,以防止任何代码重复的需要

public class BaseClass {
  public boolean equals(BaseClass other) {
    return (other.getBlahblah() == this.Blahblah && .....);
  }
}

public class DerivedClass extends BaseClass {
  public boolean equals(DerivedClass other) {
    return (super(other) && other.getNewAttribute() == this.NewAttribute.....);
  }
}

这是一个相当有效的方法。该问题存在于您的一个子类中,它必须保留由其父类约束的相等定义。否则,您将有一个中断的equals函数,这可能会导致在运行时出现一些非常独特的情况。

否,在引入与equals方法相关的新字段时,不可能遵守equals约定。有关更多信息,请参阅Joshua Bloch的“高效Java”

编辑:

class BaseClass {
    private int field1 = 0;

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof BaseClass) {
            return field1 == ((BaseClass) obj).field1;
        }
        return false;
    }
}

class BadSubClass extends BaseClass {
    private int field2 = 0;

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof BadSubClass) {
            return super.equals(obj) 
                    && field2 == ((BadSubClass) obj).field2;
        }
        return false;
    }
}

我现在手头没有这本书,但是我认为如果基类是抽象的/不能实例化的话就可以了。

我想,这非常适合提供
equals(objectobj)
hashCode()
方法实现,就像
Java
那样。我们都知道Java在基类中提供了
hashCode()和equals(Object obj)
方法实现,当需要时,我们
类中覆盖它们

看看安吉丽卡·兰格的作品

以下是一些问题的简要说明和可能的解决方案:

平等合同(除其他外)规定:

它是对称的:对于任何非空的引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)才应返回true

这意味着您可能会遇到问题,如果您的子类正在引入新字段,并且您正在将基类的对象(或另一个不重写等于的子类)与该子类的对象进行比较

不要执行以下操作:

class BaseClass {
    private int field1 = 0;

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof BaseClass) {
            return field1 == ((BaseClass) obj).field1;
        }
        return false;
    }
}

class BadSubClass extends BaseClass {
    private int field2 = 0;

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof BadSubClass) {
            return super.equals(obj) 
                    && field2 == ((BadSubClass) obj).field2;
        }
        return false;
    }
}
因为你得到了

BaseClass baseClass = new BaseClass();
BadSubClass subClass = new BadSubClass();

System.out.println(baseClass.equals(subClass)); // prints 'true'
System.out.println(subClass.equals(baseClass)); // prints 'false'
可能的解决方案:

class BaseClass {
    private int field1 = 0;

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof BaseClass) {
            return field1 == ((BaseClass) obj).field1;
        }
        return false;
    }
}

class BadSubClass extends BaseClass {
    private int field2 = 0;

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof BadSubClass) {
            return super.equals(obj) 
                    && field2 == ((BadSubClass) obj).field2;
        }
        return false;
    }
}
实例的检查替换为类比较:

obj != null && obj.getClass() == getClass()
使用此解决方案,
BaseClass
的对象永远不会等于任何子类的对象

如果创建另一个
子类
,而不使用
equals
方法的
@覆盖
,则两个
子类
-对象可以在开箱即用的情况下彼此相等(如果
基类.equals
复选框决定如此),但
子类
-对象永远不会等于
基类
-对象

一个好的实施可以如下所示:

class BaseClass {
    private int field1 = 0;

    @Override
    public boolean equals(Object obj) {
        if (obj != null && obj.getClass() == getClass()) {
            return field1 == ((BaseClass) obj).field1;
        }
        return false;
    }
}

class GoodSubClass extends BaseClass {
    private int field2 = 0;

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof GoodSubClass) {
            return super.equals(obj) && field2 == ((GoodSubClass) obj).field2;
        }
        return false;
    }
}

有关更高级的问题及其解决方案,请参阅上面提到的文章。

虽然下面的内容不能处理所有情况,但我发现它非常实用。当我同时拥有一个超类和一个子类时,我已经使用过很多次了。我不想相互比较它们,但我也不想为子类重新实现所有的超类equals()。它处理:

  • a、 等于(b)==b等于(a)
  • 不复制字段比较代码
  • 容易推广到任何子类深度
  • 子类.equals(超类)==false
  • 超类.equals(子类)==false
代码示例

// implement both strict and asymmetric equality
class SuperClass {
   public int f1;
   public boolean looseEquals(Object o) {
      if (!(o instanceof SuperClass)) return false;
      SuperClass other = (SuperClass)o;
      return f1 == other.f1;
   }
   @Override public boolean equals(Object o) {
      return looseEquals(o) && this.getClass() == o.getClass();
   }
}
class SubClass extends SuperClass {
   public int f2;
   @Override public boolean looseEquals(Object o) {
      if (!super.looseEquals(o)) return false;
      if (!(o instanceof SubClass)) return false;
      SubClass other = (SubClass)o;
      return f2 == other.f2;
   }
   // no need to override equals()
}

如果您没有正确地编写代码,将产生一个严重的问题,称为 不对称性(违反了平等合同),让我们看看我们的选择

最佳实践–同类策略。如果B是a的一个子类 每个类都有自己的equals方法,可以实现 使用相同的类策略,那么类B应该是 声明为最终版本,以防止引入不对称 在B的任何未来子类中定义相等

问题。如果我们不想让B进入决赛呢

使用组合而不是继承。每当B类和 A、 其中B是A的子类,需要不同的equals方法, 使用组合而不是继承是一个很好的策略,而且 如果B级决赛不是一种选择,那么这是唯一安全的方法 处理平等问题

怎么做


你能解释一下混合定义是什么意思吗。谢谢。在基类中有一个定义,它可能/可能不会被覆盖。我的意思是“基类定义与子类定义的混合方法”+1,因为everseen引用了Bloch。因为这是真的,所以继承是不可能的,但是组合(在有效Java的同一项中声明)+1可以建议先调用super。请注意,这不是一个有效的Java代码,更正它会很酷(我理解它可能只是一个伪代码作为示例)。谢谢。我只是把它捣碎了,没有检查大部分东西。我已经有一段时间没有使用Java了,一定是在Java中加入了一些其他语法和调用。您没有覆盖对象的equals,而是重载了Angelika Langer文章链接的iThanks。尽管这违反了利斯科夫替代原则,阿法克。再次参见Joshua Block的“有效Java”。(不过,我还没有读完整的文章。)o.getClass()有什么问题吗这个.getClass()?@Mukul我认为它实际上更好,因为如果你不做额外的检查,你就不需要重写equals方法,而且你可以调用
super.equals()
,而不会破坏一切。我刚刚提交了一个相应的编辑,在
GoodSubClass
equals()
,我们需要检查GoodSubClass的
obj实例吗?
super.equals(obj)
是否已经涵盖了这一点?