在Java中使用继承等同有什么问题?

时间:2015-07-27 13:54:14

标签: java inheritance equals

在我正在阅读的“核心Java卷1 ”一书中,它表示平等不应该与继承一起使用。所以,我有以下示例似乎有问题:

public class Main {

    public static void main(String[] args) {

        C c = new C("Test", 10);
        D d = new D("Test", 10);

        if (c.equals(d))
            System.out.println("Equal");
        else
            System.out.println("Unequal");

        if (d.equals(c))
            System.out.println("Equal");
        else
            System.out.println("Unequal");
    }
}


class C
{
    C(String cstr, int cnum) {
        str = cstr;
        num = cnum;
    }

    @Override
    public boolean equals(Object otherObject) {

        // A quick test to see if the objects are identical.
        if (this == otherObject) {
            return true;
        }

        // Must return false if the explicit parameter is null
        if (otherObject == null)
        {
            return false;
        }

        if (!(otherObject instanceof C))
            return false;

        // Now we know otherObject is a non-null Employee
        C other = (C) otherObject;

        // Test whether the fields have identical values
        return str.equals(other.str) && num == other.num;
    }

    private String str;
    private int num;
}

class D extends C {

    D(String cstr, int cnum) {
        super(cstr, cnum);
    }
}

http://ideone.com/PhFBwG

对于两个对称比较,它返回“等于”,这可能不应该。是否在派生类'D'中缺少另一个equals方法?如果是这样的话,那么上面的示例代码可能会出现什么问题,如果我根本不使用其他equals那么?

2 个答案:

答案 0 :(得分:4)

如果您希望实例CD不能与!(otherObject instanceof C)等同替换为otherObject.getClass() != this.getClass()。这样可以确保只有C可以与另一个C相等,只有D可以与另一个D相等。

这是否是你想要的取决于几个因素。我的一般经验法则是,拥有一个“开放式”平等类是一个坏主意,“外部用户”(无论对你来说意味着什么)可以添加到它。如果您希望将不同类型的对象比较为相等(并且这种情况非常罕见),则应严格控制层次结构(例如,使用final类)。

集合(和类似的明确定义的接口)是不同的:这里接口定义了一个非常精确的契约,所有实现类都需要遵循(即ArrayList如果它们可以等于LinkedList两者都以相同的顺序包含相同的元素,因为List接口定义了两个List s相等的含义。

答案 1 :(得分:4)

该代码有效,因为正如您所说,D并不会覆盖equals。我希望本书的重点是D 覆盖equals(并且它们都应覆盖hashCode),因为D个实例不应该等于C个实例,因为它们是不同的(尽管是相关的)类型。

请记住,the equals contract的一个关键方面是对称。对于nullc的任何非d值,如果c.equals(d)为真,则d.equals(c)必须为真(并且相反)。虽然这在您当前的代码中是正确的,但它可能不应该是,因为DC是不同的类型。如果D实例与C实例真正等效,为什么要D