Java类初始化顺序

来源:互联网 发布:电脑显示器改网络电视 编辑:程序博客网 时间:2024/05/22 13:51

在java编程思想中有这么一段代码,看过的人印象应该很很深刻。

package test;public class RoundGlyph extends Glyph {private int radius = 1;private int b;private int c=2;private int d;private int e;RoundGlyph(int r){radius = r;System.out.println("RoundGlyph.RoundGlyph(),radius="+radius);System.out.println("c:"+c);}void draw(){//super.draw();//当调用这个方法时候,会使用父类的方法而不会覆盖,如果注释掉,调用draw()方法时就会覆盖到父类的draw()方法System.out.println("RoundGlyph.draw(),radius="+radius);}}

package test;public class Glyph {private int a=3;private int b;private int c=3;Glyph(){System.out.println("Glyph before drwa()");draw();System.out.println("Glyph after draw()");}void draw(){System.out.println("Glyph.draw()");}}


package test;import org.junit.Test;public class PolyConstructors { @Testpublic void test() {new RoundGlyph(5);}}
代码已上传到csdn,地址:Demo

在代码的执行过程中,显示new一个对象,而这个对象是在RoundGlyph这个类中,但是因为这个类是继承自Glyph,根据继承规则,首先要从基类开始执行,debug就会发现,就本程序而言:执行初始化的过程中,先对非静态变量进行初始化,然后初始化类的构造器,在执行Glyph类的构造器的过程中,执行到draw方法的时候,因为子类RoundGlyph中也定义了draw方法,因此父类中的方法会被覆盖,当然如果不想覆盖用super即可。也就是说在执行Glyph类的构造器的过程中,执行draw方法实际上是执行的RoundGlyph中的draw方法,由于此时RoundGlyph类还没有进行非静态变量的初始化操作,因此就会发现输出语句的第二行radius=0,RoundGlyph类中的radius=1并未执行。当Glyph类的构造器执行完毕之后,基类执行完了开始继续执行子类RoundGlyph,这时候非静态变量radius=1开始初始化,变量初始化完成之后开始初始化构造器,整个过程执行完毕。最后打印输出的语句如下:



将上述代码修改成如下,更清楚明白:

package test;public class Glyph {private static String str3="父类静态变量str3初始化";private String str2="父类非静态变量str2初始化";private static String str1="父类静态变量str1初始化";static{System.out.println(str3);System.out.println(str1);System.out.println("父类静态块Glyph初始化");}{System.out.println(str2);System.out.println("父类非静态块Glyph初始化");}Glyph(){System.out.println("父类构造器Glyph初始化");draw();}void draw(){System.out.println("父类方法Glyph.draw()初始化");}}

package test;public class RoundGlyph extends Glyph {private int radius = 1;private static String str3="子类静态变量str3初始化";private String str2="子类非静态变量str2初始化";private static String str1="子类静态变量str1初始化";static{System.out.println(str3);System.out.println(str1);System.out.println("子类静态块RoundGlyph初始化");}{System.out.println(str2);System.out.println("子类非静态块RoundGlyph初始化");}RoundGlyph(int r){radius = r;System.out.println("子类构造器RoundGlyph初始化,radius="+radius);}void draw(){//super.draw();//当调用这个方法时候,会使用父类的方法而不会覆盖,如果注释掉,调用draw()方法时就会覆盖到父类的draw()方法System.out.println("子类方法RoundGlyph.draw()初始化,radius="+radius);}}

package test;import org.junit.Test;public class PolyConstructors {private static String str3="PolyConstructors类静态变量str3初始化";private String str2="PolyConstructors类非静态变量str2初始化";private static String str1="PolyConstructors类静态变量str1初始化";static{System.out.println(str3);System.out.println(str1);System.out.println("PolyConstructors静态块初始化");}{System.out.println(str2);System.out.println("PolyConstructors非静态块初始化");}  public PolyConstructors(){ System.out.println("PolyConstructors构造器初始化"); } @Testpublic void test() {System.out.println("new一个对象之前");new RoundGlyph(5);}}

打印结果如下图所示:


代码执行顺序如下:

1.父类静态变量、静态块初始化

2.子类静态变量、静态块初始化

3.父类非静态变量、非静态块、构造器初始化

4.子类非静态变量、非静态块、构造器初始化



这个过程想了几天才想明白,最后附上一篇给我启发的博客,虽然里面说的字节流看不明白,但是整体的思路还是有思考意义的。传送门

0 0
原创粉丝点击