《深入理解JAVA虚拟机》学习笔记(二)

前几天看了周志明的这本书,记录一个大纲,用以复习和备忘。

一、类的生命周期

从被加载到卸载,包括7个阶段:加载、验证、准备、解析、初始化、使用、卸载(loading, verification, preparation, resolution, initialization, using, unloading),其中验证、准备、解析统称为“连接”(Linking)。

加载、验证、准备、初始化和卸载的顺序是确定的,解析则不一定,为了支持动态绑定。

必须对类进行到“初始化”的情况:

1、用new初始化对象时、读取或设置一个类的静态字段(常量池的除外)时;

2、使用reflect包对类进行反射调用时;

3、初始化类时,需要先初始化父类(包含抽象类、接口,而如果接口初始化,并不需要其父接口初始化);

4、包含main方法的类,即程序入口;

5、关于jdk7的动态语言支持(略)

有且只有这5个方式会触发初始化,称为”主动引用“,其他称为”被动引用“

二、类加载的过程

1、加载

1、通过一个类的全限定名来获得类的二进制字节流

2、将字节流的静态存储结构转化成方法区运行时数据结构

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

以上过程灵活度很大,比如字节流加载就有很多种渠道。

对于非数组类,可以由系统提供的引导类加载器来加载,或者自定义类加载器也可以(这里的加载指加载阶段获取类的二进制流)

对于数组类,数组本身由JVM直接创建,而元素类由类加载器创建。

2、验证

连接的第一步,为了确保字节流的信息符合当前虚拟机要求,且没有危害。

主要有以下4个阶段的验证工作:

1、文件格式验证:验证字节流是否符合Class文件格式规范且能被虚拟机处理,确保字节流可以正确存储到方法区内,通过验证之后,存入方法区,不在操纵字节流。

2、元数据验证:对字节码描述的信息进行语义分析,确保符合Java语义规范,主要是类的继承关系、继承或实现 的方法是否合理。

3、字节码验证:最复杂的阶段,通过数据流和控制流分析,来验证方法的语义是否符合规范。

4、符号引用验证:发生在虚拟机将符号引用转化卫直接引用的时候,在解析阶段发生,验证引用是否符合规范,比如能否找到引用的类、是否存在访问的方法或字段、访问性(public, private, protected)是否合理。

验证阶段确保解析能正常进行,但是如果所运行的代码早已被反复验证过,则可以跳过验证阶段:-Xverify:none。

3、准备

为静态变量分配内存并初始化。初始化并没有赋值,而只是初始化为0,引用则为null。

但是如果是static final,即常量,则会赋值。

4、解析

将常量池内的符号引用替换为直接引用。

分为:

1、类或接口解析

2、字段解析

3、类方法解析

4、接口方法解析

5、初始化

类加载的最后一步,初始化类变量和其他资源,其实是执行()方法的过程。

①这个方法是由类变量所有赋值操作和静态语句块合并产生的。静态语句块不能访问定义在其后的静态变量,但是可以进行赋值操作:

public class AboutClassLoading4 {
    static {
        i = 2;
    }
    static int i;
    public static void main(String[] args) {
        System.out.println(i);//输出2
    }
}

②Object类是第一个执行这个方法的。

③由于父类先执行这个方法,所以父类的静态语句块要先于子类的变量赋值:

public class AboutClassLoading4 {
    static class Parent{
        public static int A;
        static {
            A=2;
        }
    }
    static class Sub extends Parent{
        public static int B=A;
    }
    public static void main(String[] args) {
        System.out.println(Sub.B);//输出2
    }
}

④一个类并不一定要有这个方法,比如这个类没有静态语句块和变量赋值操作。

⑤接口也会有这个方法。

⑥此方法会在多线程被加锁,同时只能有一个线程执行初始化方法。

3、类加载器

不同的类加载器对同一个类会有不同的效果。

存在两种类型的加载器:

①启动类加载器(BootStrap ClassLoader),由C++实现,是虚拟机的一部分。

将存放在\lib中的jar类库加载到虚拟机,按照文件名识别。如果自定义加载器需要委派启动类加载器,则直接用null代替。

②其他加载器,由Java实现,继承自抽象类java.lang.ClassLoader,独立于虚拟机外,包括:

扩展类加载器(Extension ClassLoader),可直接使用,负责加载\lib\ext中的类库。

应用程序类加载器(Application ClassLoader),为系统默认加载器。

双亲委派模型

(Parents Delegation Model,来自于网络,侵删)
《深入理解JAVA虚拟机》学习笔记(二)_第1张图片

工作过程:如果一个类收到加载请求,先不会自己尝试加载这个类,而是将请求委派给父类加载器,逐层委派,直到顶层的启动类加载器。当父类加载器无法完成这个类加载(没有找到要加载的类)时,子类加载器才会尝试去加载。

优点:使得同一个类会被(能够加载的)顶端的类加载器加载,确保了任意一个类的唯一性,用以保证正常加载执行。

你可能感兴趣的:(JAVA)