zoukankan      html  css  js  c++  java
  • 类加载和双亲委派机制

    类加载是什么?

    虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型

    类加载的时机?

    主动引用例子:

    1、遇到new(用new实例对象),getStatic(读取一个静态字段),putstatic(设置一个静态字段),invokeStatic(调用一个类的静态方法)这四条指令字节码命令时
    2、使用Java.lang.reflect包的方法对类进行反射调用时,如果此时类没有进行init,会先init。
    3、当初始化一个类时,如果其父类没有进行初始化,先初始化父类
    4、jvm启动时,用户需要指定一个执行的主类(包含main的类)虚拟机会先执行这个类
     
    被动引用的例子:
    1、通过子类来引用父类的静态字段,只会触发父类的初始化,不会触发子类的初始化
    2、引用一个类的静态常量不会触发初始化,因为常量在编译阶段已经确认

    类的生命周期?

    加载 loading

    >>>>连接(验证 verification 准备 preparation 解析 resolution)

    >>>>初始化 initialization

    >>>>使用 using

    >>>>卸载 unloading

    类加载过程

    加载
              1.从Class文件获取二进制字节流
              2.将字节流中的静态结构转化为方法区的运行时的动态结构
              3.在内存中生成代表该Class的java.lang.Class对象,作为方法区该类的访问入口。
    连接
              验证:验证Class文件的字节流中包含的信息是否符合JVM的要求,并确保不会危害JVM自身的安全。
              准备:为静态变量分配内存并赋初始值
              解析:将常量池内的符号引用转换为直接引用
    初始化

              调用类的clinit()方法,为静态变量赋予实际的值,执行静态代码块

    ClassLoader是什么?

    它负责将 Class 的字节码形式(本质就是一个字节数组 byte[])转换成内存形式的 Class 对象

    字节码有特定的复杂的内部格式,可以来自于磁盘文件 *.class,也可以是 jar 包里的 *.class,也可以来自远程服务器提供的字节流

    很多字节码加密技术就是依靠定制 ClassLoader 来实现的。先使用工具对字节码文件进行加密,运行时使用定制的 ClassLoader 先解密文件内容再加载这些解密后的字节码

    每个 Class 对象的内部都有一个 classLoader 字段来标识自己是由哪个 ClassLoader 加载的

    class Class<T> {
      ...
      private final ClassLoader classLoader;
      ...
    }

    延迟加载

    JVM 运行并不是一次性加载所需要的全部类,而是按需加载,也就是延迟加载

    程序在运行的过程中会逐渐遇到很多不认识的新类,这时候就会调用 ClassLoader 来加载这些类

    加载完成后就会将 Class 对象存在 ClassLoader 里面,下次就不需要重新加载了

    JVM有哪些类加载器?

    1、启动类加载器 BootstrapClassLoader 

    负责加载 JVM 运行时核心类,这些类位于 JAVA_HOME/lib/rt.jar 文件中,常用内置库 java.xxx.* 都在里面,比如 java.util.*、java.io.*、java.nio.*、java.lang.* 等等

    这个 ClassLoader 比较特殊,由 C 代码实现,称之为「根加载器」

    2、扩展类加载器 ExtensionClassLoader 

    负责加载 JVM 扩展类,它们的 jar 包位于 JAVA_HOME/lib/ext/*.jar 中,如 swing 系列、内置的 js 引擎、xml 解析器 等等,这些库名通常以 javax 开头

    3、应用程序类加载器 ApplicationClassloader(系统类加载器)

    直接面向用户的加载器,加载 Classpath 环境变量里定义的路径中的 jar 包和目录。我们自己编写的代码以及使用的第三方 jar 包通常都是由它来加载

    使用ClassLoader类的getSystemClassLoader()方法即可获取这个加载器

    双亲委派机制

    当一个类加载器收到一个类加载请求时(加载.class文件),首先会把这个任务委托给父类加载器,每个类加载器递归这个操作,

    只有在父类加载器在自己的搜索范围内找不到所需指定类时,子类加载器才会尝试自己去加载

    俗称:"儿子"先不干,先让"老子"干,"老子"再让"老子"干....,直到干不了,再依次返回让"儿子"干

    参看ClassLoader源码

    class ClassLoader {
      ...
      private final ClassLoader parent;
      ...
    }

    工作过程:

    1.当Application ClassLoader 收到一个类加载请求时,他首先不会自己去尝试加载这个类,而是将这个请求委派给父类加载器Extension ClassLoader去完成。  

    2.当Extension ClassLoader收到一个类加载请求时,他首先也不会自己去尝试加载这个类,而是将请求委派给父类加载器Bootstrap ClassLoader去完成。  

    3.如果Bootstrap ClassLoader加载失败(在<JAVA_HOME>lib中未找到所需类),就会让Extension ClassLoader尝试加载。  

    4.如果Extension ClassLoader也加载失败,就会使用Application ClassLoader加载。  

    5.如果Application ClassLoader也加载失败,就会使用自定义加载器去尝试加载。  

    6.如果均加载失败,就会抛出ClassNotFoundException异常。

     为什么要用双亲委派机制?

    1、防止重复加载同一个.class。通过委托去向上面问一问,加载过了,就不用再加载一遍
    2、保证核心.class不能被篡改。通过委托方式,不会去篡改核心.class,即使篡改也不会去加载,即使加载也不会是同一个.class对象了
    不同的加载器加载同一个.class也不是同一个Class对象。这样保证了Class执行安全。
    3、如果没有双亲委派模型而是由各个类加载器自行加载的话,如果用户编写了一个java.lang.Object的同名类并放在ClassPath中,那系统中将会出现多个不同的Object类,程序将混乱
  • 相关阅读:
    WPF数据爬取小工具-某宝推广位批量生成,及订单爬取 记:接单最痛一次的感悟
    .net core2.1
    Ng Alain使用
    MediatR
    RN错误随笔
    【转载】DDD分层架构的三种模式
    1.RN环境搭建,创建项目,使用夜神模拟调试
    ExtJs4 笔记(2) ExtJs对js基本语法扩展支持
    ExtJs4 笔记(1) ExtJs大比拼JQuery:Dom文档操作
    vue的父子通信
  • 原文地址:https://www.cnblogs.com/yb38156/p/12408708.html
Copyright © 2011-2022 走看看