虚拟机类加载机制

一.类加载的时机

    类加载过程  加载 验证 准备 解析 初始化 使用 卸载 在以下五种情况下,一定会加载类:

    1.遇到new getstatic putstatic invokestatic,则一定会初始化  所对应的有   new操作  put  get static变量 当然,这里不包括被final修饰的,因为上张提到,static final会以constantvalue的形式存储在变量类型中  以及调用static方法

    2.使用反射

    3.子类被初始化,父类还没有,那么父类会先被初始化

    4.主类会被先初始化

    5.MethodHandle实例最后的解析结果为REF_getStatic   REF_putStatic   REF_invokeStatic等时

    如果通过子类引用的是父类的static 变量,则也只会初始化父类,而不会初始化子类。

二.类加载的过程

    1.加载  加载过程中需要完成三件事   

        a.通过一个类的全限定名来获取此类的二进制字节流

        b.通过字节流代表的静态存储结构转化为方法区的运行时数据结构

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

        字节流获取的途径也多种,如下:

        a.从zip包中读取,jar  war包等

        b.网络中  applet

        c.运行时计算生成,如 反射

        d.其他文件生成,如jsp

        对于数组类,它与类加载器关系密切

        a.如果数组组件类型是引用类型,那么就要先用类加载器去加载这个类,数组会被这个类加载器类名称空间标示

        b.如果是基本类型,则数组会与引导类加载器关联

        c.数组类可见性与它的组件类型一致,如果组件类型不是引用,则会为public

    2.验证过程

        首先,文件格式校验 ,是不是java文件(魔数)版本号 常量池中类型  指向常量池的索引

        其次,对元数据验证,类是否有父类(除了object类)是否继承了不允许被继承的类 是否实现抽象类    

        再次,字节码验证,保证任意时刻操作数栈的数据类型和指令代码都能配合工作  保证不会跳转到方法以外的内容上

        最后,符号引用验证,符号引用转化为直接引用的时候,能否找到对应的类,是否有负荷的方法和字段

    3.准备

        这个阶段正式为类分配内存并设置初始变量值的过程。例如,public static int value = 123 ,会赋予初始值0,而123是在初始化过程中,才会赋予,private static final int value = 123 会被赋值123.

    4.解析阶段

        将常量池中符号引用变成直接引用的一个过程

        a.对于class或interface的解析,如果当前代码所处的类为D,想要将N转换成接口C的直接饮用       

            如果c不是数组类型,则会把代表N的全限定名传递给D的类加载器去加载这个C

            如果是数组且元素类型为对象,则重复第一条

            如果以上两步完成,C已经实现了一个有效的inteface或者class,确认D具有对C的权限,否则报错

        b.字段解析

            查找过程为,现在C本身查找,然后查找各个接口,最后查找父类,如果查找不到,则报错。

            但是如果同名字段,同时存在多个接口或者同时存在于接口和父类,那么也会报错。

        c.类方法解析

            判断是否interface,是直接报错->本身查找->父类查找->查找它实现的接口以及他们的父接口列表是否存在,存在则报错,说明是抽象类

        d.接口方法解析

            是否是类,是则报错->本身查找->父接口查找

    5.初始化

        在准备阶段,已经为变量赋过一次系统要求的初始值,而初始化执行的是<cinit>过程的方法,<cinit>方法的形成,有以下要素。

        a. init方法由编译器收集类中所有变量赋值动作和静态块内语句合并产生的,由其顺序决定。

        b.它不需要父类构造器(super方法),会保证子类的 init方法执行前,父类的已经执行完毕。

        c.父类静态块先于子类静态块执行。

        d.接口不需要执行父接口的<cinit>,只有当它要用到父接口变量时,才会调用。

        e.<cinit>方法会加锁

三.类加载器

    通过一个类的全限定名来获取此类的二进制字节流,便是类加载,实现这个动作的代码城伟类加载器。

    1.类与类加载器

       每一个类,都需要由加载它的类加载器和它本身来去定他在jvm中的唯一性。比较两个类是否相等,只有他们是同一个类加载器加载的前提下才有意义。

    2.双亲委派模式

        java虚拟机的有以下几类ClassLoader

        Bootstrap ClassLoader: 用c++编写,负责将java的核心lib加载到虚拟机中去

        Extension ClassLoader: 负责加载 java/lib/ext中内容

        Application ClassLoader:getSystemClassLoader的返回值,一般是程序中默认的加载器。

        类加载器的使用,采取了双亲委派模式:

        双亲委派模式:当需要加载一个类的时候,它会从用户自定义类,一层层委派给其父加载器来完成,只有当父加载器无法完成的时候,才会由子加载器来加载。

        双亲委派模式可以保证java的核心类无法被伪造,如果用户自己编造了java.lang.Object类,那么根据双亲委派模式,最终会委派给BootStrap ClassLoader去加载,但是BootStrap ClassLoader只会加载 /lib下面的jar包,所以最终没法找到用户自定义的Object类而失败。

转载于:https://my.oschina.net/vqishiyu/blog/1926596

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值