我有一个名为ScalarObject的类和一个名为Variable的类,该类继承自ScalarObject。我在总是返回false的ScalarObject上定义了"等于",在表示它们的字符串相等时在Variable上定义了"等于"。

如下代码:

ScalarObject a1 = new Variable("a");
ScalarObject a2 = new Variable("a");
System.out.println(a1.equals(a2));
返回false。如下代码:
Variable a1 = new Variable("a");
Variable a2 = new Variable("a");
System.out.println(a1.equals(a2));
返回true。如下代码:
ScalarObject a1 = new Variable("a");
ScalarObject a2 = new Variable("a");
System.out.println(((Variable) a1).equals(((Variable) a2)));

也返回true。问题是我还有其他一些也从ScalarObject派生的类。我的程序对象的某些部分声明为ScalarObject类型,但可以是从其派生的任何类的成员,因此将ScalarObject对象强制转换为派生类型将不起作用。例如,在程序的一部分中,我有:

protected void neighbor_simplify(LinkedList L, char op) {
...
if(n1 instanceof Variable && n2 instanceof Variable) {
System.out.println(((Variable) n1).getSymbol());
System.out.println(((Variable) n2).getSymbol());
}
if(n1.equals(n2)) { // x+x=2*x
System.out.println("B");

并且程序打印两次" x",但不打印" B"。变量n1和n2来自链接列表" L"。我怀疑程序正在调用" ScalarObject.equals()"(始终返回false),而不是" Variable.equals()"。将n1和n2强制转换为Variable类型的问题在于,n1和n2可能是也从ScalarObject派生的某些其他类的实例。我如何使程序从派生类而不是基类中调用成员,即使将其声明为基类也是如此?

我在Windows Vista上使用NetBeans 6.9.1。

网上搜索使我进入了http://wiki.answers.com/Q/Can_a_base_class_access_members_of_a_derived_class,该声明指出在Java中,使用@Override表示法时,基类可以访问派生类的成员。但是,当我将@Override添加到Variable.equals()时,出现了一条错误消息,指出该方法没有覆盖超类型的方法,这可能是因为siguatures不同。 ScalarObject.equals()接受ScalarObject类型的参数,而Variable.equals()接受Variable类型的参数。

问题是所有equals方法的签名应该相同。 我假设您正确定义了它们。

你怀疑错了。 如果.methodName左侧对象的类为DerivedClass,则将调用DerivedClass中methodName的版本(假设签名匹配)。 引用变量的声明的类不影响此。

根据约书亚·布洛赫(Joshua Bloch)的说法,继承的主要问题之一是"您不能在不破坏平等合同的情况下向继承的类中添加价值成分"。 在我看来,equals(Object o)主要用于使面向对象的程序员的生活更加痛苦。

必须将equals方法在所有类中都定义为public Object equals(Object obj),以便它们正确覆盖(提示,请听@Override注释编译错误)。

您应该非常小心覆盖和重载之间的区别。

如果基类和派生类中的equals方法的签名匹配(应该是这种情况,请参阅jtahlborn的答案),那么您已经覆盖了。这使用动态绑定:在运行时确定正确的equals方法,因此

ScalarObject a1 = new Variable("a");
a1.equals(...);
调用Variable的等值项,因为a1的类型在运行时确定为Variable。
如果equals方法的签名不匹配(equals(ScalarObject so)与equals(Variable v)),则说明您有重载。这使用静态绑定。也就是说,即使您这样做
Variable a1 = new Variable("a");
ScalarObject a2 = new Variable("a");
a1.equals(a2);

最后一行将使用ScalarObject.equals(ScalarObject so),因为编译器无法推断a2的类型为Variable。

长话短说:始终对您的equals方法使用覆盖,即使用public boolean equals(Object o)。

您要在此处执行的操作是,通过更改变量的签名以接受ScalarObject,然后使Variable的equals方法重写ScalarObject.equals,然后使用instanceof运算符根据传入对象的实际类型采取不同的操作。

不,您不希望equals方法采用标量对象。