JVM 类加载初始化过程

一、需明白的几个概念

实例的初始化方法

就是我们说的构造器,构造器就包括 构造方法、{}包住的代码等。

类的初始化方法

1、()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{}语句)中的语句合并产生的,编译器收集的顺序是有语句在源文件中出现的顺序所决定的,静态语句块中只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块中可以赋值,但不能访问。

2、()方法与类的构造函数(实例化()方法)不同,他不需要显示地调用父类构造器,虚拟机会保证在子类的()方法执行之前,父类的()方法执行完毕。虚拟机第一个被执行的()方法肯定是java.lang.Object()。

3、由于父类的()方法先执行,所以父类定义的静态语句块要优先于子类的变量赋值操作。

4、如果一个类中没有静态语句块,也没有对变量的赋值操作,编译器不必为类生成()方法。

5、接口不能使用静态语句块,但仍有变量初始化的赋值操作,会生成()方法。接口的()方法不需要先执行父类接口的()方法,当父类接口中定义的变量被使用时,父接口才会被初始化。接口的实现类在初始化时不会执行接口的()方法。

6、一个类的()方法在多线程环境中执行时,只会有一个线程去执行()方法,其余线程都需要阻塞等待,直到活动线程执行()方法完毕。

init is the (or one of the) constructor(s) for the instance, and non-static field initialization.

clinit are the static initialization blocks for the class, and static field initialization.

是instance实例构造器,对非静态变量解析初始化。而是class类构造器对静态变量,静态代码块进行初始化

 

加载顺序

当一个类初始化的时候,先调用方法 ,如果在方法中遇到方法。则先调用完方法。然后在继续执行

 

二、看几个例子

public class Test {
    {
        System.out.println("构造块1");
    }
    static {
        System.out.println("静态块");
    }
    {
        System.out.println("构造块2");
    }
    public static void main(String[] args) {
    }

}
---------------------- out -------------------------
静态块

-----------------------编译----------------------------
public class com.up366.contentcheck.a.Test {
  public com.up366.contentcheck.a.Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       7: ldc           #3                  // String 构造块1
       9: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      12: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      15: ldc           #5                  // String 构造块2
      17: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      20: return

  public static void main(java.lang.String[]);
    Code:
       0: return

  static {};
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #6                  // String 静态块
       5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return
}

----------------分析---------------------
可以看出我们不进行实例的初始化,静态代码依旧得到了执行,这是由于进行了类的初始化。
public class Test {
    {
        System.out.println("构造块1");
    }
    public Test(){
        System.out.println("构造方法");
    }
    static {
        System.out.println("静态块");
    }
    {
        System.out.println("构造块2");
    }
    public static void main(String[] args) {
        Test c = new Test();
    }
}

---------------------- out -------------------------
静态块
构造块1
构造块2
构造方法

-----------------------编译----------------------------
public class com.up366.contentcheck.a.Test {
  public com.up366.contentcheck.a.Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       7: ldc           #3                  // String 构造块1
       9: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      12: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      15: ldc           #5                  // String 构造块2
      17: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      20: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      23: ldc           #6                  // String 构造方法
      25: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      28: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #7                  // class com/up366/contentcheck/a/Test
       3: dup
       4: invokespecial #8                  // Method "":()V
       7: astore_1
       8: return

  static {};
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #9                  // String 静态块
       5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return
}

---------------------------分析------------------------------
根据结果可以看出新进行了类初始化,然后进行了实例的初始化。
我们需要同时明白实例的初始化方法就是静态块、构造块1、构造块2的输出,而不包括静态代码块,那是类的初始化部分

 

public class Test {
    static Test A = new Test();
    static Test B = new Test();
    {
        System.out.println("构造块1");
    }
    public Test(){
        System.out.println("构造方法");
    }
    static {
        System.out.println("静态块");
    }
    {
        System.out.println("构造块2");
    }
    public static void main(String[] args) {
        Test c = new Test();
    }
}

----------------------- out -------------------------
构造块1
构造块2
构造方法
构造块1
构造块2
构造方法
静态块
构造块1
构造块2
构造方法

-----------------------编译----------------------------
public class com.up366.contentcheck.a.Test {
  static com.up366.contentcheck.a.Test A;

  static com.up366.contentcheck.a.Test B;

  public com.up366.contentcheck.a.Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       7: ldc           #3                  // String 构造块1
       9: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      12: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      15: ldc           #5                  // String 构造块2
      17: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      20: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      23: ldc           #6                  // String 构造方法
      25: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      28: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #7                  // class com/up366/contentcheck/a/Test
       3: dup
       4: invokespecial #8                  // Method "":()V
       7: astore_1
       8: return

  static {};
    Code:
       0: new           #7                  // class com/up366/contentcheck/a/Test
       3: dup
       4: invokespecial #8                  // Method "":()V
       7: putstatic     #9                  // Field A:Lcom/up366/contentcheck/a/Test;
      10: new           #7                  // class com/up366/contentcheck/a/Test
      13: dup
      14: invokespecial #8                  // Method "":()V
      17: putstatic     #10                 // Field B:Lcom/up366/contentcheck/a/Test;
      20: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      23: ldc           #11                 // String 静态块
      25: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      28: return
}
-----------------------------------------分析--------------------------
根据编译后代码看,首先进行了类的初始化方法。
类的初始化中首先进行了static Test A = new Test();这句,
那么就会进行new进行实例的初始化方法,
实例的初始化方法就是我们上个例子中说的那三句输出构造块1、构造块2、构造方法
然后进行static Test B = new Test();
最后进行静态代码块的输出。
至此类的初始化完成,接下来进行实例的初始化
Main()方法中的 Test c = new Test();等于号后面的new Test()
这同样也是实例的初始化方法,输出构造块1、构造块2、构造方法

 

 

 

 

 

你可能感兴趣的:(Java)