zoukankan      html  css  js  c++  java
  • JVM系列(二):Java类的加载机制

    一、概念

    1.  字节码:

    a. 以前的代码(例如C++)编译后是本地机器码,不同的机器编译出来的机器码是不同的

    b. Java编译后是相同的字节码文件,即存放在.class文件中的二进制文件,JVM可以执行任何符合规范的字节码文件

    2. 类加载机制:将描述类的二进制数据从.class文件读入内存的不同区域中,并对数据进行校验、转换、解析和初始化,最终形成可以让JVM直接使用的Java类型

    3. 类加载结果:在堆区创建了一个java.lang.Class对象,用来封装类在方法区内的数据结构

    4. 允许预加载

    5. 可控性强,可用自定义的类加载器完成加载

    二、加载.class文件的方式

    1. 从本地系统中直接加载

    2. 通过网络下载.class文件

    3. 从zip,jar等归档文件中加载.class文件

    4. 从专有数据库中提取.class文件

    5. 将Java源文件动态编译为.class文件

    三、类的生命周期:加载->(验证->准备->解析)链接->初始化->使用->卸载

    1. 加载,如上所述

    2. 链接

    a. 验证:确保被加载的类的正确性

    b. 准备:为类的静态变量分配内存,而不是实例变量;并初始化为数据类型的默认值,而不是代码中赋予的值;为static final赋代码中的值

    c. 解析:把类中的符号引用改为直接引用

    3. 初始化:为静态变量初始化实际的值,JVM对类和类变量初始化

    4. 卸载

    四、类加载器ClassLoader:通过一个类的全限定名来获取描述此类的二进制字节流,这个动作在JVM外部实现,以便让程序自己决定如何去获取所需的类

    1. 启动类加载器,BootStrap ClassLoader

    a. 由C++实现,是虚拟机的一部分,其他类加载器都由Java实现,以便让程序自己决定如何去获取所需的类

    b. 加载JAVA_HOME/lib目录中的类(JAVA_HOME指明JDK安装路径),或者-Xbootclasspath参数所指定的路径中的类,并且被JVM按照文件名识别的,例如JRE/lib/rt.jar

    2. 扩展类加载器,Extension ClassLoader,加载JAVA_HOME/lib/ext目录下的类,或者被java.ext.dirs系统变量所指定的路径下的类。关键词:ext

    3. 应用程序类加载器,Application ClassLoader

    a. 程序中默认的类加载器,除非自定义了类加载器

    b. 加载用户路径(ClassPath)上的类

    c. 是ClassLoader中,getSystemClassLoader方法的返回值

    4. 用户自定义类加载器,User ClassLoader,加载编程人员制定的目录下的类

    5. 从JVM的角度来看,类加载器分为两类:BootStrap类加载器(JVM里的C++实现)、其他类加载器(外部Java实现)。

    6. 从开发人员角度,分为3类:启动类加载器、扩展类加载器、应用类加载器

    五、类与类加载器的关系

    1. 类加载器虽然只用于实现类的加载动作,但它在Java程序中的作用,却远远不限于类加载阶段

    2. 类本身+加载这个类的类加载器=Java虚拟机中的唯一性,用于比较类是否相等

    六、类的加载方式

    1. 命令行启动应用时,由JVM初始化加载

    2. 通过Class.forName()方法动态加载:将.class文件加载到JVM中,执行类中的static块

    3. 通过ClassLoader.loadClass()方法动态加载,只加载.class文件

    七、双亲委派模型

    1. 如果一个类加载器收到了类加载的请求,它首先把请求委托给父加载器去完成,依次向上,只有父加载器无法完成时,才由子加载器完成。

    2. 上述过程完成后,如果AppClassLoader加载失败,会抛出ClassNotFoundException

    3. 作用:解决了基础类的统一问题,防止内存中出现重复的字节码,保证Java程序安全执行。例如用户编写了java.lang.Object类,并放在ClassPath中,系统中会有多个Object类,就混乱了。

    4. 类加载器间的父子关系不是继承,而是组合

    5. 实现过程:即java.lang.ClassLoader中的loadClass()方法,递归调用父加载器,最终是findClass()方法完成加载操作

    6. 自己写一个类加载器去加载java.lang.Object或者java.lang.String类

    八、破坏双亲委派模型

    1. 双亲委派模型不是强制要求,而是建议性的类加载机制

    2. 双亲委派模型的缺点:一般情况下,基础类是被用户代码调用的;特殊情况下,基础类会调用用户的代码,例如JNDI服务

    3. 线程上线文类加载器(Thread Context ClassLoader),可以通过java.lang.Thread类中的setContextClassLoader()方法设置,父加载器请求子加载器去完成加载

    4. 破坏双亲委派机制的场景:

    a. 涉及SPI的加载动作,例如JNDI、JDBC、JBI

    b. 热拔插、热部署、模块化,增减模块时不需要重启,只需要把此模块和类加载器一起去掉

    九、自定义类加载器

    1. 应用场景:用网络传输加密的字节码

    2. 使用方法:继承ClassLoader类,并重写findClass()方法

  • 相关阅读:
    Java 简单算法--打印乘法口诀(只使用一次循环)
    Java简单算法--求100以内素数
    ubuntu 16.04 chrome flash player 过期
    java 网络API访问 web 站点
    java scoket (UDP通信模型)简易聊天室
    leetcode1105 Filling Bookcase Shelves
    leetcode1140 Stone Game II
    leetcode1186 Maximum Subarray Sum with One Deletion
    leetcode31 Next Permutation
    leetcode834 Sum of Distances in Tree
  • 原文地址:https://www.cnblogs.com/june0816/p/8011570.html
Copyright © 2011-2022 走看看