Java继承的初始化与构造函数的执行顺序问题
2014-10-08 23:39
579 查看
我们知道在Java中,创建一个对象,先要执行各成员变量的定义初始化,然后执行构造函数。
当然,在Java继承中,我们也知道,先要执行父类的构造函数,再执行子类的构造函数。
但是,对于父类对象,和子类对象成员变量的定义初始化的执行顺序我们却不是很了解,大部分书上,也没有说明。为此,我们只有自己写测试程序,从而,了解Java是如何处理继承的执行顺序的问题。
下面献上一个测试程序:
public class C extends B {
private D item=new D();
public C(){
System.out.println("C()");
}
public static void main(String[] args)
{
C item=new C();
}
}
class A{
A(){
System.out.println("A()");
}
}
class B {
private A item=new A();
B(){
System.out.println("B()");
}
B(int i){
System.out.println("1");
}
}
class D{
D(){
System.out.println("D()");
}
}
该程序的输出结果是:
A()
B()
D()
C()
对此,我做出了猜想:
继承的子类执行顺序是:父类构造函数,子类成员初始化,子类构造函数。
或者是,(父类默认构造函数,子类成员初始化,子类构造函数(若函数内有super(...),执行父类对应的构造函数))。
可能,对于第二个猜想有人觉得莫名其妙,但是,在看到测试结果时,笔者的第一感觉是,Java是按第二种顺序做的。
下面我们为了验证那个猜想是正确的,我们做了另一个测试程序,如下:
public class C extends B {
private D item=new D();
public C(){
super(1);
System.out.println("C()");
}
public static void main(String[] args)
{
<pre name="code" class="html"><span style="white-space:pre"> </span>C item=new C(); }}class A{A(){System.out.println("A()");}}class B {private A item=new A();B(){System.out.println("B()");}B(int i){System.out.println("1");}}class D{D(){System.out.println("D()");}}
运行结果:
A()
1
D()
C()
看到这样的结果,瞬间知道了Java编译器是怎样做的了。
我们现在理一下,程序的运行过程,
首先程序的入口时main()函数:
第一步,读到:
C item=new C();编译器寻找,C的类定义,编译器看到:
public class C extends B编译器意识到,C是一个继承子类,所以,先要构造一个父类对象,可父类对象如何构造呢,编译器找到C的构造函数,查看构造函数的第一句代码:
super(1);
(这也就是,Java为什么只能在构造函数的第一句写super(...)的原因)
所以,编译器就以 new B(1)的方式,创建B的对象。进入B的类定义,先要进行成员变量定义初始化·:
private A item=new A();所以,创建A对象,进入类A,调用:
System.out.println("A()");输出:
A()
然后,调用B的构造函数:
System.out.println("1");输出:
1
再去做C的成员变量定义初始化:
private D item=new D();输出:
D()
最后,做C的构造函数:
注意,super(1)的使命已经完成,所以编译器此时会忽略这一句话。
输出:
C()
以我们的猜想退出编译器的完成过程,可能整个编译过程分析是有问题的,不过,可以很好地帮助我们分析问题
当然,在Java继承中,我们也知道,先要执行父类的构造函数,再执行子类的构造函数。
但是,对于父类对象,和子类对象成员变量的定义初始化的执行顺序我们却不是很了解,大部分书上,也没有说明。为此,我们只有自己写测试程序,从而,了解Java是如何处理继承的执行顺序的问题。
下面献上一个测试程序:
public class C extends B {
private D item=new D();
public C(){
System.out.println("C()");
}
public static void main(String[] args)
{
C item=new C();
}
}
class A{
A(){
System.out.println("A()");
}
}
class B {
private A item=new A();
B(){
System.out.println("B()");
}
B(int i){
System.out.println("1");
}
}
class D{
D(){
System.out.println("D()");
}
}
该程序的输出结果是:
A()
B()
D()
C()
对此,我做出了猜想:
继承的子类执行顺序是:父类构造函数,子类成员初始化,子类构造函数。
或者是,(父类默认构造函数,子类成员初始化,子类构造函数(若函数内有super(...),执行父类对应的构造函数))。
可能,对于第二个猜想有人觉得莫名其妙,但是,在看到测试结果时,笔者的第一感觉是,Java是按第二种顺序做的。
下面我们为了验证那个猜想是正确的,我们做了另一个测试程序,如下:
public class C extends B {
private D item=new D();
public C(){
super(1);
System.out.println("C()");
}
public static void main(String[] args)
{
<pre name="code" class="html"><span style="white-space:pre"> </span>C item=new C(); }}class A{A(){System.out.println("A()");}}class B {private A item=new A();B(){System.out.println("B()");}B(int i){System.out.println("1");}}class D{D(){System.out.println("D()");}}
运行结果:
A()
1
D()
C()
看到这样的结果,瞬间知道了Java编译器是怎样做的了。
我们现在理一下,程序的运行过程,
首先程序的入口时main()函数:
第一步,读到:
C item=new C();编译器寻找,C的类定义,编译器看到:
public class C extends B编译器意识到,C是一个继承子类,所以,先要构造一个父类对象,可父类对象如何构造呢,编译器找到C的构造函数,查看构造函数的第一句代码:
super(1);
(这也就是,Java为什么只能在构造函数的第一句写super(...)的原因)
所以,编译器就以 new B(1)的方式,创建B的对象。进入B的类定义,先要进行成员变量定义初始化·:
private A item=new A();所以,创建A对象,进入类A,调用:
System.out.println("A()");输出:
A()
然后,调用B的构造函数:
System.out.println("1");输出:
1
再去做C的成员变量定义初始化:
private D item=new D();输出:
D()
最后,做C的构造函数:
注意,super(1)的使命已经完成,所以编译器此时会忽略这一句话。
输出:
C()
以我们的猜想退出编译器的完成过程,可能整个编译过程分析是有问题的,不过,可以很好地帮助我们分析问题
相关文章推荐
- 【java】构造函数的继承执行顺序
- Java对象的构造过程---子类继承父类时(非)静态块及构造函数等的执行顺序
- Java类初始化顺序问题:静态初始化块,非静态初始化块以及构造函数
- Java的块,静态块,构造函数,继承的执行先后顺序
- Java类中静态属性、静态语句块、属性、初始化语句块、构造函数之间的执行顺序
- java 继承类 变量、静态变量、构造函数执行顺序
- Java中 构造函数与初始化块的执行顺序
- java变量,初始化快,构造函数的执行顺序
- 又一波 有关 java 静态代码块 代码块 构造函数执行顺序问题
- Java的初始化块、静态初始化块、构造函数的执行顺序及用途探究
- java变量,初始化快,构造函数的执行顺序
- java变量,初始化快,构造函数的执行顺序
- java变量,初始化快,构造函数的执行顺序
- Java继承,在构造函数内对父类初始化的问题
- JAVA 继承 构造函数的执行顺序
- 关于继承类执行构造函数的顺序问题
- java变量,初始化快,构造函数的执行顺序
- 【java】构造函数的继承执行顺序
- java变量,初始化快,构造函数的执行顺序
- java变量,初始化快,构造函数的执行顺序,运算符的优先级(从高到低)