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