一、在类的内部,变量定义的先后顺序决定了初始化的顺序。即使变量定义散布于方法定义之间,它们仍旧会在任何方法(包括构造器)被调用之前得到初始化。即:先变量后方法。 比如如下的java程序:
class Tag { Tag(int marker) { System.out.println("Tag(" + marker + ")"); } } class Card { Tag t1 = new Tag(1); // Before constructor Card() { // Indicate we're in the constructor: System.out.println("Card()"); t3 = new Tag(33); // Reinitialize t3 } Tag t2 = new Tag(2); // After constructor void f() { System.out.println("f()"); } Tag t3 = new Tag(3); // At end } public class OrderOfInitialization { public static void main(String[] args) { Card t = new Card(); t.f(); // Shows that construction is done } }程序运行结果为: Tag(1) Tag(2) Tag(3) Card() Tag(33) f()
这个很简单,不多说。就是有一个地方需要注意,每次构造类的对象的时候,程序先跳到的是类的构造函数但是并不执行,然后跳到类中的第一个变量处执行。这个有什么区别,请先想一想,之后的列三会回答。
二、静态数据初始化,先静态,再非静态。
java程序如下:
class Bowl { Bowl(int marker) { System.out.println("Bowl(" + marker + ")"); } void f(int marker) { System.out.println("f(" + marker + ")"); } } class Table { static Bowl b1 = new Bowl(1); Table() { System.out.println("Table()"); b2.f(1); } void f2(int marker) { System.out.println("f2(" + marker + ")"); } static Bowl b2 = new Bowl(2); } class Cupboard { Bowl b3 = new Bowl(3); static Bowl b4 = new Bowl(4); Cupboard() { System.out.println("Cupboard()"); b4.f(2); } void f3(int marker) { System.out.println("f3(" + marker + ")"); } static Bowl b5 = new Bowl(5); } public class StaticInitialization { public static void main(String[] args) { System.out.println("Creating new Cupboard() in main"); new Cupboard(); System.out.println("Creating new Cupboard() in main"); new Cupboard(); t2.f2(1); t3.f3(1); } static Table t2 = new Table(); static Cupboard t3 = new Cupboard(); }程序运行结果为: Bowl(1) Bowl(2) Table() f(1) Bowl(4) Bowl(5) Bowl(3) Cupboard() f(2) Creating new Cupboard() in main Bowl(3) Cupboard() f(2) Creating new Cupboard() in main Bowl(3) Cupboard() f(2) f2(1) f3(1)
这里需要注意的是静态变量只初始化一次。
三、构造器的调用顺序 1. 调用基类构造器。这个步骤会不断地反复递归下去,首先是构造这种层次结构的根,然后是下一层导出类,等等。直到最低层的导出类。 2. 按声明顺序调用成员的初始状态设置模块。 3. 调用导出类构造器的主体。
java程序如下:
class Meal { Meal() { System.out.println("Meal()"); } } class Bread { Bread() { System.out.println("Bread()"); } } class Cheese { Cheese() { System.out.println("Cheese()"); } } class Lettuce { Lettuce() { System.out.println("Lettuce()"); } } class Lunch extends Meal { Lunch() { System.out.println("Lunch()"); } } class PortableLunch extends Lunch { PortableLunch() { System.out.println("PortableLunch()"); } } public class Sandwich extends PortableLunch { private Bread b = new Bread(); private Cheese c = new Cheese(); private Lettuce l = new Lettuce(); public Sandwich() { System.out.println("Sandwich()"); } public static void main(String[] args) { new Sandwich(); } }运行结果为: Meal() Lunch() PortableLunch() Bread() Cheese() Lettuce() Sandwich()
这里有些同学就会有疑问了,对于主类为什么不是例一所说的先变量后方法,然后先输出 Bread() Cheese() Lettuce() 其实主类最先会执行main方法,然后main方法中生成一个Sandwich()对象。之后就是例一我所强调的,程序会先跳到主类对象的构造方法(不执行),然后发现主类是继承自PortableLunch()的子类,就会先构造PortableLunch(),即执行PortableLunch()的构造方法。同上,直到找到最初的基类Meal(),构造之。也就会先输出 Meal() Lunch() PortableLunch() 再进行先变量后方法,即输出 Bread() Cheese() Lettuce() 最后是主类对象的构造方法,输出 Sandwich()
四、在其他任何事物发生之前,将分配给对象的存储空间初始化成二进制的零。
java程序如下:
abstract class Glyph { abstract void draw(); Glyph() { System.out.println("Glyph() before draw()"); draw(); System.out.println("Glyph() after draw()"); } } class RoundGlyph extends Glyph { private int radius = 1; RoundGlyph(int r) { radius = r; System.out.println("RoundGlyph.RoundGlyph(), radius = " + radius); } void draw() { System.out.println("RoundGlyph.draw(), radius = " + radius); } } public class PolyConstructors { public static void main(String[] args) { new RoundGlyph(5); } }程序运行结果为: Glyph() before draw() RoundGlyph.draw(), radius = 0 Glyph() after draw() RoundGlyph.RoundGlyph(), radius = 5
这个结果按前面的说的方法就很容易得出。