2013-02-01 155 views
6

我非常困惑重写构造函数。构造函数不能被覆盖的是结果,当我在谷歌搜索它是什么让我的问题是覆盖构造函数

public class constructorOverridden { 

    public static void main(String args[]) { 
     Sub sub = new Sub(); 
     sub.test(); 
    } 
} 

class Super { 
    Super() { 
     System.out.println("In Super constructor"); 
     test(); 
    } 

    void test() { 
     System.out.println("In Super.test()"); 
    } 
} 

class Sub extends Super { 
    Sub() { 
     System.out.println("In Sub constructor"); 
    } 

    void test() { // overrides test() in Super 
     System.out.println("In Sub.test()"); 
    } 
} 

当我运行此我得到的结果作为

In Super constructor 
In Sub.test() 
In Sub constructor 
In Sub.test() 

请注意在子类中的测试方法被执行。它是否显示超类构造函数被覆盖。它是否正确?

回答

19

构造函数不是多态的 - 你不需要覆盖它们。您在子类中创建了新的构造函数,并且每个子类构造函数都必须链接(可能间接)到超类构造函数。如果您没有明确地链接到构造函数,则会在子类构造函数主体的开始处插入对无参数超类构造函数的隐式调用。

现在在重写方法 - 一个对象从一开始就是它的“最终类型”,包括执行超类构造函数时。因此,如果您在Super构造函数代码中打印getClass(),则在输出中仍会看到Sub。其结果是被调用的覆盖方法(即Sub.test),即使Sub构造函数尚未执行。

这基本上是一个坏主意,你应该总是避免构造函数调用可能-重写方法 - 或文档很清楚,这将是情况(这样子类代码意识到它可以”不依赖于已经适当初始化的变量等)。

+0

那么,在避免“在构造函数中调用重载方法”时应该使用什么方法?我试图完成的是超类构造函数调用抽象方法init(),build()和fill()的基本流程。所以,所有的子类都必须经历相同的流程! – Akshat

+0

@Akshat:好吧,这听起来像是属于“非常明显的文档”类别。通常有一些*设计的方式,但很难给出一个通用的配方。 –

+0

如果你可以给这些方式链接,那会很棒! – Akshat

3

构造函数的第一个隐含行是对Super()的调用。这就是为什么你得到这些结果。

3

这是正确的。在实例化子类时,首先调用超类构造函数,然后调用层次结构中的每个连续构造函数。

在上例中,超类构造函数调用覆盖的方法(test())。这是有效的,但是由于没有调用子类的构造函数,所以潜在的危险,并且你的子类不会被完全初始化。由于这个原因,在构造函数中调用重写的(或可重写的)方法并不是很好的做法。

2

它不覆盖超类的构造函数,构造函数不能被覆盖它可以被重载。

当你创建子类对象时,超类将首先被​​实例化,然后子类将被实例化。它像没有父母的孩子不能存在

编译器会自动从子类构造函数中调用超类构造函数。

Sub() { 
    super(); 
    System.out.println("In Sub constructor"); 
} 
4

您不能重写构造函数,因为构造函数是由它构造的类的名称调用的。你怎么能用相同的构造函数创建一些不同的类?另外,子类不会从其父类继承构造函数。

如果父类的构造做了一些重要的初始化,可以从孩子的构造使用超叫:

class Err extends Throwable { 
    Err(String message) { 
     super(message); // Call the constructor of Throwable. 
     .. 

父类的构造也总是叫。如果你自己没有调用任何方法,那么在输入派生类的构造函数之前会自动调用一个不带参数的构造函数。如果父项没有无参数构造函数,并且没有调用任何构造函数,则会报告编译时错误。