Java:将对象声明为基类时访问派生类的成员

时间:2013-06-04 19:19:56

标签: java inheritance

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

以下代码:

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<ScalarObject> 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类型的参数。

3 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:0)

你要做的是让变量的equals方法通过改变它的签名来覆盖ScalarObject,然后使用instanceof运算符根据传入对象的实际类型采取不同的动作。覆盖ScalarObject.equals。

答案 2 :(得分:0)

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

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

ScalarObject a1 = new Variable("a");
a1.equals(...);

调用Variable的等于,因为a1的类型在运行时被确定为Variable


如果equals方法的签名不匹配(equals(ScalarObject so) vs 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)