一、JVM探索之类的初始化顺序

0、本文要点:

  • 类的生命周期
  • 类的初始化顺序
  • 总结

1、类的生命周期

  首先谈到类的初始化过程,就不得不复习一下类的生命周期

  类的生命周期如下:

  (1)加载

  (2)链接:1??验证;2??准备;3??解析

  (3)初始化

  (4)使用

  (5)卸载

2、类的初始化顺序

  (1)解释

  这里我们所说的初始化顺序,其实是一个class文件里各个部分的执行顺序

  (2)结论

  前提:加载类方法(注意是加载)  

  第一步:

    发生在链接-准备阶段的初始化:

    1)为类常量(static final)赋正式值

    2)为类变量赋默认值(注意是系统默认值,不是代码给定的初始值)

 

    注意:类变量、静态代码块的执行顺序按代码顺序从上到下,代码块放在前面会先执行代码块,但此时代码块,可以对下面的类变量赋其他值,但是如果不能对类变量进行读取操作,否则会报 error: illegal forward reference(不合法的向前引用),这个道理也适用在对象变量和普通代码块中间。

  第2步:

    1)发生在初始化阶段的类变量赋初始值

      执行静态代码块

  第3步:

    1)发生在使用阶段,如果new了对象

      1??成员变量、普通代码块初始化

      2??构造器

  直接上代码:

public class Main {
    public static void main(String[] args) {
        System.out.println("Hello, World");
        son.method();//静态方法调用 执行1、2
        //new son(); //对象调用 执行1、2、3、4
    }
}

class son{
    //2、静态块1
    static{
        i = 666;
        System.out.println("静态代码块1");
    }
    //1、静态变量 i\j,常量k赋默认值 
    //2、静态变量 i\j赋值初值值
    static int i;
    static int j = 2;
    static final int k = 3;

    //2、静态块2    
    static{
        System.out.println("静态代码块2");
        j = 444;
        System.out.println("i = " + i + ",j = " + j + ",k = " + k); //i = 666,j = 444,k = 3
    }

    //4、构造器    
    public son(){
        a = 112;
        System.out.print("构造器"  + ",j = " + j);
        System.out.print("构造器"  + ",a = " + a);
    }
    
    //3、成员变量
    int a = 111;

    //3、普通代码块    
    {
        System.out.print("代码块1");
        b = 444;
        System.out.println("a = " + a );
        //System.out.println("a = " + a + ",b" +b); //error: illegal forward reference  指b
    }
    
    int b = 333;
    
    public static void method(){
        System.out.print("静态方法");
        i = 333;
        System.out.println("i = " + i + ",j = " + j + ",k = " + k); //i = 333,j = 444,k = 3
    }
    
}

3、对于有继承关系的类初始化过程:

一、JVM探索之类的初始化顺序

 

 

 总结一句初始化来说就是:先父后子,先类(静态)后对象,对象构方法在最后。

 

另外附一道面试题,帮助了解类加载

public class Test {
    public static void main(String[] args) {
        A a = A.getInstance();
      /*解题原则:类只加载一次,因此类变量只初始化一次,
      A:
      先执行类的实例化,此时需要类的初始化
      然后类变量 value2 执行一次赋值
      B:
      先执行类的初始化,其中value2已经赋值,然后在执行对象定义,此时不会再初始化value1\value2
      */ System.out.println(
"A value1:" + a.value1);//1 System.out.println("A value2:" + a.value2);//0 B b = B.getInstance(); System.out.println("B value1:" + b.value1);//1 System.out.println("B value2:" + b.value2);//1 } } class A{ private static A a = new A(); public static int value1; public static int value2 = 0; private A(){ value1++; value2++; } public static A getInstance(){ return a; } } class B{ public static int value1; public static int value2 = 0; private static B b = new B(); private B(){ value1++; value2++; } public static B getInstance(){ return b; } }

 

一、JVM探索之类的初始化顺序

上一篇:activiti并发多实例子流程任务处理


下一篇:北鲲云超算平台能够为药物研发提供哪些层面的解决方案?