类加载过程
这主要涉及到类加载的过程,类加载的过程主要分为三个大的过程加载、连接(验证、准备、解析)和初始化。
对类中的值进行操作的过程主要是连接阶段的准备过程和初始化。连接准备阶段
连接准备阶段
准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。这个阶段中有两个容易混淆的概念需要强调一下。首先这时候进行内存分配的仅包括类变量(被static修饰的变量),而不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在Java堆中。其次,这里所说的初始值是数据类型的0值:
public static int value=123;
这时候在准备阶段过后初始值为0,而不是123,因为这时候还尚未开始执行任何Java方法,而把value赋值为123的putstatic指令是程序被编译后,存放于类构造器()方法中,所以把value赋值为123的动作将在初始化阶段才会执行。其实还有另外一些情况如果类字段的字段属性表中存在ConstantValue属性,那么在准备阶段变量的值就会被初始化为ConstantValue属性所指定的值。
public static final int value=123;
另外就是初始化阶段
在准备阶段,变量已经赋值过一次系统要求的初始值,而在初始化阶段,则根据程序员通过指定的主观计划去初始化类变量和其他资源,或者可以从另外一个角度来表达:初始话节点是执行类构造器方法的过程clinit(),
类初始化阶段是类加载过程的最后异步,前面的类加载过程中,除了在加载阶段用户应用程序可以通过自定义类加载器参与之外,其余动作完全由虚拟机主导和控制。到了初始化阶段才真正开始执行类中定义的Java程序代码(或者说是字节码)
在准备阶段,变量已经赋值过一次系统要求的初始值,而在初始化阶段,则根据程序员通过指定的主观计划去初始化类变量和其他资源,或者可以从另外一个角度来表达:初始话节点是执行类构造器方法的过程(),
()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块static{}块中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序所决定的,静态语句块中只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块可以赋值但是不能访问(非法的向前引用),()方法的类构造函数(或者说实例构造器()方法不同,他不需要显示地调用父类构造器),虚拟机保证在子类的()方法执行之前,父类的()方法已经执行完毕。因此虚拟机中第一个被执行的()方法的类肯定是java.lang.Object
执行顺序
父类静态代码块
子类静态代码块
父类构造代码块
父类构造函数
子类构造代码块
子类构造函数
这里举个例子方便理解
父类
public class SuperClass {
public int value;
public static int staticValue;
static {
//1
System.out.println("11111111111111111111111111111111111111111111");
System.out.println("SuperClass静态代码块"+staticValue);
staticValue=11;
}
{
//3
System.out.println("33333333333333333333333333333333333333333333333333");
System.out.println("SuperClass构造代码块"+value);
value=11;
}
public SuperClass() {
//4
System.out.println("4444444444444444444444444444444444444444444444444");
System.out.println("SuperClass()构造函数value"+value);
System.out.println("SuperClass()构造函数staticValue"+staticValue);
value=22;
staticValue=22;
}
}
子类
public class SubClass extends SuperClass {
static {
//2
System.out.println("222222222222222222222222222222222222222222222");
System.out.println("SubClass()静态代码块staticValue"+staticValue);
staticValue=33;
}
{
//5
System.out.println("555555555555555555555555555555");
System.out.println("SubClass()构造代码块value"+value);
value=33;
}
public SubClass() {
//6
System.out.println("66666666666666666666666666666666");
System.out.println("SubClass()构造函数value"+value);
System.out.println("SubClass()构造函数staticValue"+staticValue);
staticValue=44;
value=44;
}
}
验证类(执行)
public class InitRange {
public static void main(String[]args){
new SubClass();
}
}
执行结果