JAVA构造类的过程

本文代码块参考代码部分博客
本文JVM原理部分参考原理部分博客

JVM运行java代码原理部分

class HelloApp
{
 public static void main(String[] args)
 {
  System.out.println("Hello World!");
  for (int i = 0; i < args.length; i++ )
  {
   System.out.println(args[i]);
  }
 }
}

JAVA构造类的过程_第1张图片
1.开始试图执行类HelloApp的main方法,发现该类并没有被虚拟机装载,也就是说虚拟机当前不包含该类的二进制代表(也就是javac后的class文件)。
2.虚拟机使用ClassLoader试图寻找这样的二进制代表。如果这个进程失败,则抛出一个异常。
3.类被装载后同时在main方法被调用之前,必须对类HelloApp与其它类型进行链接然后初始化。
链接包含三个阶段:检验,准备和解析。
3.1、检验检查被装载的主类的符号和语义
3.2、准备和创建类或接口的静态域以及把这些域初始化为标准的默认值,这部分就静态的默认初始化
3.3、解析负责检查主类对其它类或接口的符号引用,比如继承了父类。在这一步它是可选的。

类的初始化是对类中声明的静态初始化函数和静态域的初始化构造方法的执行。一个类在初始化之前它的父类必须被初始化

下面开始用程序验证这一个过程

public class Print {

     public Print(String s){
         System.out.print(s + " ");
     }
 }

  public class Test1 {

      public static Print obj1 = new Print("1");

      public Print obj2 = new Print("2");

      public static Print obj3 = new Print("3");

      static{
         new Print("4");
     }
     public static Print obj4 = new Print("5");

     public Print obj5 = new Print("6");

     public Test1(){
         new Print("7");
     }

 }

  public class Test2 extends Test1{

      static{
          new Print("a");
      }

      public static Print obj1 = new Print("b");

      public Print obj2 = new Print("c");

     public Test2(){
         new Print("d");
     }

     public static Print obj3 = new Print("e");

     public Print obj4 = new Print("f");

     public static void main(String [] args){
         Test1 obj1 = new Test2();
         Test1 obj2 = new Test2();
     }
 }

结果是:1 3 4 5 a b e 2 6 7 c f d 2 6 7 c f d
执行main方法,程序输出顺序为:
obj1: 1 3 4 5 a b e 2 6 7 c f d
obj2: 2 6 7 c f d
输出结果表明,程序的执行顺序为:
如果类还没有被加载:
1、先执行父类的静态代码块和静态变量初始化,并且静态代码块和静态变量的执行顺序只跟代码中出现的顺序有关。(输出1 3 4 5)
2、执行子类的静态代码块和静态变量初始化。(输出 a b e)
3、执行父类的实例变量初始化(输出 2 6)
4、执行父类的构造函数(输出 7)
5、执行子类的实例变量初始化(输出 c f)
6、执行子类的构造函数(输出d)
如果类已经被加载:
则静态代码块和静态变量就不用重复执行,再创建类对象时,只执行与实例相关的变量初始化和构造方法。(输出 2 6 7 c f d)

你可能感兴趣的:(java基础学习)