jvm-类的加载过程

马德兰的博客

1. 概述

从类的生命周期而言,一个类包括如下阶段:

afsdgsdgdsgsdsa.jpg

加载、验证、准备、初始化和卸载这5个阶段的顺序是确定的,类的加载过程必须按照这种顺序进行,而解析阶段则不一定,它在某些情况下可能在初始化阶段后在开始,因为java支持运行时绑定。

2. 类的加载过程

2.1 加载

1.通过一个类的全限定名获取此类的二进制字节流(从内存中读出)
2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
3.在内存中生成一个代表这个类的java.lang.class对象,作为方法区这个类的各种数据访问入口

2.2 链接

链接包括验证、准备、解析三个部分

验证:目的在于确保class文件的字节流中包含信息复合当前虚拟机的要求,保证被加载类的正确性。主要包括四种验证,文件格式的验证,元数据验证,字节码验证,符号引用验证。

准备:为类变量分配内存并且设置该变量的默认初始值,即零值,这里不包含final修饰的static,因为final在编译的时候就会分配,准备阶段就会显示初始化,这里不会为实例变量分配初始化(即一个类内定义的类对象),类变量会分配在方法区中,而实例变量会随着对象一期分配到java堆中。

解析:将常量池中的引用转化为直接引用,往往解析操作会在伴随着jvm在执行完初始化之后再执行。将常量池中的符号引用转化为直接引用的过程.主要针对类或者接口,字段.类方法.接口方法,方法类型

:符号引用就是一组符号来描述所引用的目标,符号引用的字面量形式明确定义在《java虚拟机规范》的class文件格式中。

2.3 初始化

1.初始化阶段就是执行类构造器的过程,静态变量和代码块会执行显示赋值

2.若该类有父类jvm会保证父类的初始化构造器先执行

3.jvm会将该方法在多线程下被加锁

3. 类加载器

jvm支持两种类加载器:一种是引导类加载器(Bootstrap ClassLoader)和自定义类加载器(所有派生于抽象类classloader的类加载器都成为自定义类加载器.

image20200723164040929.png

3.1 常用的类加载器有三个

public class HelloDemo {
    public static void main(String[] args) {
        /*获取系统的类加载器*/
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);

        /*获取其上层加载器:扩展类加载器*/
        ClassLoader exClassLoader = systemClassLoader.getParent();
        System.out.println(exClassLoader);

        /*继续获取其上层*/
        ClassLoader bootClassLoader = exClassLoader.getParent();
        System.out.println(bootClassLoader);

        /*用户的自定义类加载器*/
        ClassLoader UserclassLoader = HelloDemo.class.getClassLoader();
        System.out.println(UserclassLoader);

        /*string类使用的类加载器*/
        ClassLoader strClassLoader = String.class.getClassLoader();
        System.out.println(strClassLoader);
    }
}
//sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@14ae5a5
null
sun.misc.Launcher$AppClassLoader@18b4aac2
null

由上述代码可得:用户的自定义类都是用系统默认类加载器进行加载,java核心类库使用引导类加载器进行加载.

  • 引导类加载器:使用c和c++实现,嵌套在jvm内部并不继承classloader类没有父加载器,只加载包名以java,javax,sun开头的类, \lin目录下的文件 比如rt.jar,tools.jar.

  • 扩展类加载器:父类为引导类加载器,加载从jdk安装目录中的jre/ib/ext子目录下加载类库,用自定的jar包放在此目录也会被加载,由sun.misc.Launcher$ExtClassLoader类实现.

  • 应用程序类加载器:他负责加载环境变量classpath和系统属性java.class.path指定下的类库,系统默认类加载器,通过ClassLoader.getSystemClassLoader()获取,由sun.misc.Launcher$AppClassLoader实现.

3.2 获取类加载器

//扩展类加载器Main,获取class文件进而获取类加载器
        ClassLoader classLoader = MainTest.class.getClassLoader();
        //表示当前线程的类加载器——应用程序类加载器
        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
        //—启动类加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();

3.3 双亲委派机制

java虚拟机对class文件采用的是按需加载方式,而且加载某个类的class文件,Java虚拟机才用的是双亲委派模式:即请求交给父类处理,它是一种任务委派模式

类加载器的双亲委派模型如下

70.jpg

根据类加载器流程图,当需要查找一个class对象时候,由于类加载机制只要加载过该类,就不需要去重新加载,只需要查找缓存
1、缓存路:查找自身加载器是否有缓存,没有则委托父类AppClassLoader加载器---->查找AppClassLoader加载器是否有缓存,没有则委托父类ExtClassLoader---->查找ExtClassLoader加载器是否有缓存,没有则委托BoopStrap加载器–>查找BoopStrap加载器是否有缓存,没有则开始加载(在任何一个加载器中该类已经加载,则直接返回)
2、加载路:如果一个类加载器受到类加载请求,他并不会自己先去加载而是委托给父类加载器去加载,如果父类还有父类继续向上委托然后到达顶层开始加载,
即最后BoopStrap在核心库中加载,如果未加载成功---->ExtClassLoader在lib/ext中加载,如果未加载成功----->AppClassLoader在当前classpath中加载,如果未加载成功---->自定义加载器加载,如果未加载成功---->抛出异常ClassNotFoundException
是否能加载根据该加载器能加载的路径判断.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值