02月28, 2018

虚拟机类加载过程-初始化

流程

  

graph LR
加载-->验证
验证-->准备
准备-->解析
解析-->初始化
初始化-->使用
使用-->卸载

初始化

  java虚拟机规范,所有java虚拟机实现必须在每个类或接口被java程序首次主动使用时才初始化。
主动使用的几种情况:

  • 创建类的实例
  • 访问某个类或者接口的静态变量,或者对该静态变量赋值(如果访问静态编译时常量(即编译时可以确定值的常量)不会导致类的初始化)
  • 调用类的静态方法
  • 反射(Class.forName(xxx.xxx.xxx))
  • 初始化一个类的子类(相当于对父类的主动使用)
  • Java虚拟机被标明为启动类的类(包含main方法的)

  看下面的实例

package chapter7.classload.initialization;

public class TestClass {
    private String name;

    public static final int price=10;

    static {
            System.out.println("Initializing");
    }

    TestClass() {
            System.out.println("Building");
    }

    TestClass(String name) {
            this.setName(name);
    }

    public static String playToy(String player) {
            String msg = player + " plays " ;
            System.out.println(msg);
            return msg;
    }

    public void setName(String name) {
        this.name = name;
    }

}

测试类:

package chapter7.classload.initialization;

public class RunTest1 {

    public static void main(String[] args) throws ClassNotFoundException {
      // 对上面的类,执行下面的代码:
      Class<?> c = Class.forName("chapter7.classload.initialization.TestClass");
      // c.newInstance();
    }

}

输出:

Initializing

问题
  初始化时仅会初始静态代码块(static{}块中)的语句所有类变量的赋值动作,以下面代码为例,输出结果B的值为2

static class Parent {
    public staic int A = 1;
    static {
        A = 2;
    }
}
static class Sub extends Parent {
    public static int B = A;
}

public static void main(String[] args) {
    System.out.println(Sub.B);
}

分析
   Parent是Sub的父类,查看本文开头的规范初始化一个类的子类(相当于对父类的主动使用),所以会初始化Parent类,但初始化时仅会初始化静态代码和类变量赋值,所以,会执行static { A = 2; }, 所以B = 2了

本文链接:https://www.daguanren.cc/post/java_vm_classload_initialization.html

-- EOF --

Comments