Java类加载过程

Java在类加载时会进行一些动作,比如初始化等等,了解类的加载过程能够使我们在写代码时避免一些错误的发生。

类加载分为四个过程,分别为加载,验证,准备,解析,初始化

加载

1)通过一个类的全限定名来获取定义此类的二进制字节流。

2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。

3)在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。

验证

验证是连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。从整体上看,验证阶段大致上会完成下面4个阶段的检验动作:文件格式验证、元数据验证、字节码验证、符号引用验证。

准备

准备阶段是正式为类变量分配内存并设置类变量(static修饰)初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。
两种情况:

  1. 普通类变量(static):初始化值,int赋0,boolean赋false,引用类型赋null等
  2. 常量类变量(static final):初始化为指定的值

解析

将符号引用转化为直接引用

初始化

初始化阶段是执行类构造器<clinit>()方法的过程。

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

public class Test{
static{
i=0;//给变量赋值可以正常编译通过
System.out.print(i);//这句编译器会提示"非法向前引用"
}
static int i=1;
}

下面代码的输出是1。下面语句的赋值覆盖了上面语句。

public class Test{
    static{
        i=0;
    }
    static int i=1;

    public static void main(String[] args) {
        System.out.print(i);

    }
}
先初始化父类

<clinit>()方法与类的构造函数(或者说实例构造器<init>()方法)不同,它不需要显式地调用父类构造器,虚拟机会保证在子类的<clinit>()方法执行之前,父类的<clinit>()方法已经执行完毕。因此在虚拟机中第一个被执行的<clinit>()方法的类肯定是java.lang.Object。

你可能感兴趣的:(java,SE)