JVM-类加载

9 篇文章 0 订阅
1 篇文章 0 订阅

1、类加载过程概述

java程序的运行环境,从一开始的硬盘中的一堆二进制文件,到内存中的java运行时的整个环境的构成,这里依靠着JVM中一个极其重要的概念,就是类加载,依靠类加载器,java得以从一堆二进制数据变成了一个可以运行的java环境。
类加载:就是将硬盘中二进制的class文件,加载到内存中,并连接到java的运行环境中。
类加载分为三个步骤:

  • 1-加载:加载这一步骤,很简单,就是单纯的将二进制的class文件,搬运到内存中。说的更实际点,就是指,将class文件读取到内存中,可以以byte数组的方式,暂存到内存中。
  • 2-连接:连接这一步,主要的工作就是将读到内存中的class类数据,进行一系列操作,集成进当前的java环境中,这一步又分成了三个小步骤
    • 2-1验证:这一步骤主要是检查当前加载进内存的class类数据是否符合class文件规范(比方说文件的头是不是0xCAFEBABE这四个字节,每个class文件的头四个字节称为魔数,中文总是叫咖啡宝贝、主次版本号是否咋爱当前虚拟机的处理范围之内等等),这里的验证是有必要的,如果对class文件进行读取的化,class文件中的内容实际上还是部分可读的。
    • 2-2准备:这一步骤主要是为类变量(就是类中的静态变量,不用实例就可以通过类获取到的变量)分配内存,同时设置默认值,这里的默认值,不是程序中赋的值,而是这个类型的变量,jvm固定的默认初始值,比如bool变量就赋值为false,int变量就赋值为0,Integer变量就赋值为null;
    • 2-3解析:这一步骤就是将符合引用替换为直接引用
  • 3-初始化:这一步骤,就是将上一步骤中被赋零值的类变量赋上程序中提供的值。

2、类的使用

  • java对类的使用分为两种:

    • 主动使用
    • 被动使用
  • 所有的java虚拟机实现必须在每个类或接口被java程序“首次主动使用”时才初始化它们
    主动使用分为七种情况:

    1. 创建类的实例
    2. 调用类的静态方法
    3. 调用使用类的静态变量,或对类的静态变量复制
    4. 反射,例如使用Class.forName(“com.example”)加载类
    5. 子类被初始化时,作为父类也必须被初始化
    6. java虚拟机启动时被标为启动类的类(比方说Java Test)
    7. jdk1.7中提供的动态语言支持,java.lang.invoke.MethodHandle实例的解析 结果句柄对应的类会被初始化

    除了以上情况,其他使用java的情况都不会被初始化(比方说类加载器ClassLoader.loadClass()、在程序中显示调用子类的父类中的静态常量)
    上述过程中主要是针对类的初始化条件,但是在针对接口时,又会有所不同
    当java虚拟机初始化一个类的时候,要求它的所有父类都已近被初始化,但是这条规则并不适用于接口

  • 在初始化一个类时,并不会先初始化它所实现的接口

  • 在初始化一个接口时,并不会i初始化它的父接口
    因此,一个父接口并不会因为它的子接口或者实现类的初始化而初始化。只有当程序首次使用特定接口的静态变量时,才会导致该接口的初始化。(这里很大一部分原因时接口中的变量默认都是静态常量,会由类的常量池的原因导致父接口不会被初始化)

3、类加载器

jvm定义区分了两种类型的类加载器

  • java虚拟机自带的加载器
    • 根类加载器(Bootstrap):sun.boot.class.path
    • 拓展类加载器(Extension):java.ext.dirs
    • 系统(应用)类加载器(System):java.class.path
  • 用户自定义的类加载器
    • 继承自java.lang.ClassLoader的子类
    • 用户可以定制类的加载方式

上述的类加载是一种层级上的父子关系,但不是简单的继承关系。
类加载器在加载类时,如果出现错误,这个错误只有等到程序首次主动使用该类的时候才会报告错误(linkageError错误)。
根类加载器时由C++语言编写的,是拓展类加载器的父加载器。
拓展类加载器是系统类加载器的父加载器,这两种类加载器是java类(Launcher类的内部类),这两个类加载器作一个类是被根类加载器加载进jvm运行时环境的。

jvm在加载类时遵循双亲委托机制,但是这种机制存在部分缺陷,所以jvm又提供了线程上下文类加载器,由于有时候父类加载器加载某些子类加载器的类不可见,那么父类加载器加载的类就会通过ServerceLoader,去调用存在当前线程中的ThreadContextClassLoader(TCCL)去加载子类加载器所加载的类,这种做法在SPI(Serveice provider interface)中普遍存在。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值