Java不一致继承机制?

Java不一致继承机制?,java,oop,inheritance,Java,Oop,Inheritance,我想我们已经在这里讨论过这个问题了 但是,因为这里的例子有点简单,我想澄清的是不同的一点,所以我将尝试一下 首先,要讨论的两个类: public class SuperClass{ SuperClass() { foo(); } public void foo() { System.out.println("Super.foo()"); } public static void main(String[] args) {

我想我们已经在这里讨论过这个问题了

但是,因为这里的例子有点简单,我想澄清的是不同的一点,所以我将尝试一下

首先,要讨论的两个类:

public class SuperClass{
    SuperClass() {
        foo();
    }

    public void foo() {
        System.out.println("Super.foo()");
    }

    public static void main(String[] args) {
            SuperClass tn = new DerivedClass();
            tn.foo();
    }
}

public class DerivedClass extends SuperClass{
    String i;

    TrickyB() {
        i = "aksjhdf";
    }

    public void foo() {
        System.out.println("In derived.foo() --> " + i);
    }
}
我(至少我认为)理解多态性的概念,我知道调用时调用
DerivedClass.foo()
的原因

new DerivedClass();
我在这里看到了一个矛盾:

当我们调用
DerivedClass
的c'tor时,
超类
的c'tor被隐式调用(也就是说作为派生c'tor的第一行)

因此,在Super c'tor中,
DerivedClass
没有完全初始化,这使得使用此类变得毫无用处。 这一点反映在该程序的输出中

In derived.foo() --> null
In derived.foo() --> aksjhdf
第一行反映了我的困惑:

为什么要调用
DerivedClass.foo()
?物体还没有准备好,所以用它做任何事在我看来都是胡说八道

谁能给我解释一下原因吗。我认为这绝对违反直觉

顺便说一句:我本来希望调用
SuperClass.foo()
,因为正如我所说的,使用“未完成”对象没有任何意义

另一方面:在我看来。这对我来说也没有任何意义,当我在超类的c'tor中时,
DerivedClass.foo()
被调用


在我的情况下,如何调用
超类.foo()

为什么调用DerivedClass.foo()?

因为这是Java语言设计。开发人员自己负责确保继承层次结构中的不变类,而不是语言

在我的情况下如何调用SuperClass.foo()?

从派生类:
super.foo()

为什么要调用DerivedClass.foo()?物体还没有准备好,所以用它做任何事在我看来都是胡说八道

否。该对象已创建。构造函数不创建对象,它只是初始化它们。对象是由这里的
new
操作符创建的

我希望调用超类.foo()

如前所述,并不是没有创建对象。已经有了。该调用将调用重写的方法。这就是为什么。你会看到意想不到的行为

超类
对任何派生类都一无所知

不需要知道。方法调用调用派生类方法的事实与超类是否知道子类无关。将被调用的实际方法是在运行时根据图片中的实际对象确定的。由于此处的对象类型为
DerivedClass
,因此将调用
DerivedClass
中的方法(如果存在)

在我的例子中,如何调用超类.foo()


你没有。这就是重点。通过与我链接的帖子,一步一步的解释。

< P>不同于C++,java在运行任何构造函数之前,在分配时设置对象的运行时类型。这就是在初始化期间发生多态行为的原因


在受控的情况下,这种行为有时是有用的。但是,在大多数情况下,最好避免这样做,因为您正在将未初始化的对象泄漏给类外部的代码(通过虚拟方法中的
this
引用)。尽可能只从构造函数中调用私有(或最终)方法。

DerivedClass.foo()在DerivedClass中调用。将为对象本身调用foo()。通过继承,它也可以等于超类.foo()。但是,由于多态性也可以不同。如果您明确地想要超类中的foo(),那么调用super.foo()。顺便说一句,因为DerivedClass.foo()依赖于i,所以应该首先初始化i。

正如Rohit所说,不应该从构造函数调用重写的方法(或者更准确地说,可以重写的方法)。这里有一个解决方法:

public class SuperClass{
    SuperClass() {
        privateFoo();
    }

    public void foo() {
        privateFoo();
    }

    private void privateFoo() {   // cannot be overridden since it's private
        System.out.println("Super.foo()");
    }

}

foo
方法设为调用私有版本的单行方法。当然,如果它有参数和/或返回值,你应该包括它们。

+1千万不要让
这个
引用从构造函数中泄漏出来:)谢谢你的分步解释。我知道DerivedClass已经存在(但尚未初始化),困扰我的是在它不可用时访问它的可能性。@TomasLongo这就是问题所在。Java不会阻止你做这些事情。可能是因为识别这些类型的内容并将其标记为某个错误对于编译器来说是不可行的。有些事情你必须处理。