java中的类的初始化顺序详解

来源:互联网 发布:双拼cn域名价格 编辑:程序博客网 时间:2024/05/17 20:22

  在java中一切都是对象的概念,我们无时无刻不在创建对象使用对象,理解对象的创建过程是非常重要的,那么接下来我们就来聊一聊在java中如何从无到有的创建一个对象。假设我们有一个名为Dog的类:

  1. 我们都知道在java中构造器的被隐式声明为静态,调用静态方法必须要通过类名。当首次创建对象的时候,或者是类中的静态内容(包括方法和域)首次被访问的时候,java解释器必须首先查找类路径,来定位Dog.class。
  2. 然后,就再入class文件,执行全部的静态初始化工作。静态初始化工作仅仅在class文件首次被调用的时候执行。
  3. 当使用new Dog()创建对象的时候,应该在堆上分配足够的存储空间。
  4. 堆相应的存储空间置零,这样Dog中的primitive type就被默认初始化了,引用被默认初始化为null。
  5. 执行类中字段定义的初始化(显式实例化)。
  6. 执行构造器。如果这个这个类没有采用继承的机制,那么类的定义就被完成了。如果有继承机制,那么按照从超类(根)到子类以此初始化的顺序执行。

  这样堆砌一堆文字看上去不那么直观,我们还是通过一个例子来加深你对上面过程的理解和记忆。

// import static System.out;class Meal {      {          System.out.println("begin_1");      }      static Cheese l=new Cheese();      private Bread b=new Bread();      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 {      static Lettuce l=new Lettuce();      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) {        System.out.println("begin");        new Sandwich();      }}   /* Output:1--Cheese()2--Lettuce()3--begin4--begin_15--Bread()6--Meal()7--Lunch()8--PortableLunch()9--Bread()10--Cheese()11--Lettuce()12--Sandwich()

  我们来分析一下上面的执行结果:

  1. 从输出结果1和2我们可以看出,程序首先执行的是对Sandwich继承体系中的所有类,按照从上到下的顺序初始化其中的静态域。
  2. 然后开始执行main方法中的语句,输出3。
  3. 接着,又在main方法中定义了一个Sandwich临时对象,那么再次从继承体系中,按照从上至下的顺序进行构造,即依次构造Meal,Lunch,PortableLunch,Sandwich。(6、7、8)
  4. 对于每一个对象而言,依次执行非静态实例域和初始化块(这两者没有先后顺序)(可以调整4、5相关的顺序进行验证),然后调用对应类的构造函数。(9、10、11、12)

  通过对上面例子的研究,我们可以得出这样一个结论,在研究关于执行顺序的问题的时候,我们一般会采用通过输出反应执行结果的方法。例如在这里例子中,我们想要看,静态实例域和实例域以及各自的构造函数在整个继承层次中是怎样被执行的,我们给每一个变量设置不同的输出,通过最终的输出结果,执行顺序就一目了然了。

0 0
原创粉丝点击