父构造函数调用的方法表现为子方法

Method called by parent constructor behaves as child method

提问人:GeorgeTheGood 提问时间:7/23/2017 更新时间:7/23/2017 访问量:1161

问:

我正在 java 中测试一些多态性,我的代码如下所示:

class Base {
        int value = 0;
        public Base(){
            System.out.println("Came Here And Value is: " + value);
            addValue();
        }
        String addValue(){
            System.out.println("Calling Bases' addValue and value is currently: " + value);
            value += 10;
            return "";
        }
        int getValue(){
            return value;
        }
}
class Derived extends Base{
        public Derived(){
            System.out.println("Calling Derived constructor and value currently is: " + value);
            addValue();
        }
        String addValue(){
            System.out.println("Came to Deriveds' addValue and value now is: " + value);
            value += 20;
            return "";
        }
        int getValue(){
            return value;
        }
}
public class MyClass {
    public static void main(String [] args){
       Base b = new Derived();
       System.out.println(b.getValue());

    }
}

所以这里的问题是,它打印 40,但我猜它应该打印 30。我的想法是:new Derived 首先调用 new Base,它调用 和 (定义在 Base 中将值加以 10)当时值应该是 10。然后,调用 Derived's,使值为 30(因为 Derived 中的定义将值增加了 20)。但相反,Base 调用了它子的 .有人可以解释发生了什么吗?addValue()addValue()addValue()addValue()addValue()

Java 多态 性层次结构

评论


答:

1赞 Andrew Tobilko 7/23/2017 #1

是的,这是多态性如何工作的一个很好的例子。

由于重写了子方法,因此此处从不调用父方法。这称为虚拟方法调用。因此,如果子方法被调用两次,结果将是 。addValue40

评论

0赞 GeorgeTheGood 7/23/2017
请问另一个问题。如果我将 value 变量更改为 static,并且如果我将 addValue() s 都更改为 static,则打印 30。那么发生了什么?
0赞 Andrew Tobilko 7/23/2017
@GeorgeTheGood,它被称为方法隐藏。这里没有与实例的连接,因此从定义它的上下文中调用类方法
4赞 Sweeper 7/23/2017 #2

你思维过程中的误解被加粗了:

new Derived 首先调用 new Base,后者调用 addValue() 和 (因为 Base 中定义的 addValue() 将 value 相加 10)此时 value 应为 10。 然后,调用 Derived 的 addValue(),使值为 30(因为 Derived 中定义的 addValue() 将值增加 20)。

虽然被放置在基类构造函数中,但它仍然调用 ,如下所示:addValueaddValuethis

this.addValue();

嗯,什么是?它是一个类实例。派生类有什么作用?它增加了 20。这就是为什么你得到 40 个。thisDerivedaddValue

评论

0赞 GeorgeTheGood 7/23/2017
请问另一个问题。如果我将 value 变量更改为 static,并且如果我将 addValue() s 都更改为 static,则打印 30。那么发生了什么?
0赞 Sweeper 7/23/2017
@GeorgeTheGood 这是因为静态方法不受多态性的影响。 放置在基类中的构造函数将调用 .addValueBase.addValue
1赞 Mr. Wrong 7/23/2017 #3

这是因为 Derived 对 super 进行了隐式调用,但它将调用 Derived 中覆盖的 addvalue。这就是为什么不应在构造函数中调用可重写方法的原因。

您可以通过在 main() 的第一行上创建一个断点来找到这一点,并让调试器向您显示步骤。

评论

0赞 GeorgeTheGood 7/23/2017
再快点请。如果我将 value 变量更改为 static,并且如果我将 addValue() s 都更改为 static,则打印 30。那么发生了什么?
1赞 user207421 7/23/2017 #4

在这方面,Java 的行为与 C++ 不同。在 C++ 中,当父构造函数执行时,对象仅被视为部分构造,因此它将执行父构造函数的方法。在 Java 中,它将始终执行该方法最派生的实现。

评论

0赞 GeorgeTheGood 7/23/2017
再快点请。如果我将 value 变量更改为 static,并且如果我将 addValue() s 都更改为 static,则打印 30。那么发生了什么?
0赞 user207421 7/23/2017
因此,它从 和 从 调用,因为静态方法不会被覆盖。Base.addValue()Base()Derived.addValue()Derived()