Java - 子类调用超级构造函数,它调用子类方法而不是自己的方法

时间:2013-11-21 09:26:33

标签: java inheritance methods constructor override

我将从代码示例开始:

class A {
    public A() {
        f(); //When accessed through super() call this does not call A.f() as I had expected.
    }

    public void f() {} //I expect this to be called from the constructor.
}

class B extends A {
    private Object o;

    public B() {
        super();
        o = new Object(); //Note, created after super() call.
    }

    @Override
    public void f() {
        //Anything that access o.
        o.hashCode(); //Throws NullPointerException.
        super.f();
    }
}

public class Init {
    public static void main(String[] args) {
        B b = new B();
    }
}

此程序会抛出NullPointerException。当对象b进入其超类A的构造函数并调用被类B f()覆盖的方法B.f()时,而不是A.f()我原以为是。

我认为一个超类不应该知道它是否是子类,但是一定可以用一个类告诉它是否已经被子类化了?这背后的原因是什么?如果我真的希望调用A.f()而不是B.f(),是否有任何解决方法?

提前致谢。


跟进问题:

感谢您的回答。我现在明白为什么会这样,但这是一个后续问题。也许我错了,但是子类型的原则是超类型不应该知道它已被子类型化。这个“机制”让一个类知道它是否已经被子类化。请考虑以下代码示例:

class A {
    private boolean isSubclassed = true;

    public A() {
        f(); //A.f() unsets the isSubclassed flag, B.f() does not.
        if(this.isSubclassed) {
            System.out.println("I'm subclassed.");
        } else {
            System.out.println("I'm not subclassed.");
        }
    }

    public void f() {
        this.isSubclassed = false;
    }
}

class B extends A {
    public B() {
        super();
    }

    @Override
    public void f() {}
}

public class Init {
    public static void main(String[] args) {
        new B(); //Subclass.
        new A();
    }
}

该程序的输出是:

I'm subclassed.
I'm not subclassed.

这里A知道它已经被子类化了。它不为人知,但无关紧要。这是怎么解释的?我被误导了吗?

4 个答案:

答案 0 :(得分:2)

发生NullPointerException因为在构造B的实例时,会调用父构造函数(在A中)。此构造函数调用f()方法,但由于对象的实际类型为B,因此调用B中的重写f()方法。

@Override
public void f() {
    //Anything that access o.
    o.hashCode(); //Throws NullPointerException as o has not been initialised yet
    super.f();
}

这里的教训是永远不要在构造函数中调用一个可以被子类覆盖的方法。

答案 1 :(得分:1)

这就是为什么你不应该从构造函数调用非私有方法。除了将方法设为私有之外,没有解决方法。

答案 2 :(得分:0)

这就是覆盖隐藏自己方法的原因。在f()类构造函数的super调用时,它隐藏了super类方法调用。实际上是调用subclass覆盖方法。

 class A{
 public A() {
    f(); // It call the subclass overided method.
  }
 // This method is hide due to override.
  public void f() {
    } 
 }

class B extends A {
// This method is called before constructor where Object o is Null, hence you
// got NullPointerExcetion.
@Override
public void f() {
    // Anything that access o.
    o.hashCode(); // Throws NullPointerException.
    super.f();
 }
}

答案 3 :(得分:0)

class A {
    public A() {
             System.out.println(1);
         f(); 
             // where super(),this will be called by subclass ,but subclass's o is null 
    }
    public void f() {
        System.out.println(4);
    }
}