什么是类加载机制?

虚拟机把描述类的数据从Class文件加载到内存,并对数据进行,校验,转换解析,初始化,最终形成可以被java虚拟机直接使用的java类型,这就是虚拟机的类加载机制
与一般的编译语言不同,在java语言里面,类的加载,解析,链接,初始化等都是在运行时动态进行的,这样虽然有一些性能开销,但是为java语言提供了很大的灵活性

类加载时机

类文件被加载到内存中开始,卸载出内存为止,它的整个生命周期包括,
加载 > 验证 > 准备 > 解析 > 初始化 > 使用 > 卸载,其中 加载,验证,准备,初始化,卸载这几个顺序是确定的,但是解析可能不是(解析是指把常量池中的符号引用,替换成直接引用的过程),它在某些情况下可能,初始化之后才开始执行,这是为了支持java的运行时绑定,比如多态情况下。
什么时候开始类加载机制的第一个阶段:加载? 虚拟机中并没有明确规定,但是对于初始化阶段,虚拟机严格规定了5种情况必须对类进行初始化

  • 1 遇到new, getstatic, putstatic, 或者 invokestatic 这4条字节码指令时,分别对应java 的 new 创建对象,使用用static变量,设置static变量,或者调用static方法时
  • 2 使用java.lang.reflect包的方法对类进行反射调用的时候
  • 3 当初始化一个类的时候,如果发现其父类没有被初始化,则先初始化其父类
  • 4 当虚拟机启动时,包含main方法的那个类,虚拟机会先初始化这个类
  • 5 当使用jdk1.7的动态语言支持时,如果一个java.lang.invoke.MethodHander的实例最后解析结果为REF_getStatic, REF_putStaic, REF_invokeStaitc方法的句柄,但是这个句柄对应的实体类没有被初始化,那么要先触发其初始化
    这5种情况被称为类的主动引用,除此之外的任何其他引用类的方式都不会触发初始化 例如
public class SupperObj {static {System.out.println("supper obj 被初始化");}public static String f = "hello,world";
}
public class TestObj extends SupperObj {static {System.out.println("TestObj 被初始化");}
}
调用该方法只会输出 supper Obj 被初始化
对于子类引用父类的静态字段,只有直接定义这个字段的类会被初始化
String t =  TestObj.f;例2
TestObj [] testObjs = new TestObj[0];
执行该代码并没有输出  TestObj 被初始化
说明并没有触发 com.haojiangbo.test.TestObj 的初始化阶段
查看字节码发现 对应的是 anewarray   指令,
这个字节码,不属于主动引用的五种情况的范畴
附 字节码stack=1, locals=2, args_size=10: iconst_0
关键     1: anewarray     #2                  // class com/haojiangbo/test/TestObj4: astore_15: return例3
public class SupperObj {static {System.out.println("supper obj 被初始化");}public static final String f = "hello,world";
}
String t =  TestObj.f;
该代码也不会触发类的初始化,因为编译的时候,常量已经预编译到
类文件的常量池里了,所以不存在对 SupperObj  任何引用关系
附 字节码
Constant pool:#1 = Methodref          #5.#21         // java/lang/Object."<init>":()V#2 = Class              #22            // com/haojiangbo/test/TestObj常量池已经包含 这个字符串#3 = String             #23            // hello,worldCode:stack=1, locals=2, args_size=1加载常量池中的字符串0: ldc           #3                  // String hello,world赋值到本地变量表 slot 1 的位置  java代码 String t =  TestObj.f;2: astore_13: returnLineNumberTable:line 5: 0line 6: 3LocalVariableTable:Start  Length  Slot  Name   Signature0       4     0     a   [Ljava/lang/String;3       1     1     t   Ljava/lang/String;

接口的加载过程,和类加载过程有些区别,接口的初始化,并不会引起其父接口的初始化

public interface Inteface1 {String a = Test.print("1");
}
public interface Inteface2  extends  Inteface1{String b = Test.print("2");
}
public class TestObj  implements Inteface2{static {System.out.println("TestObj 被初始化");}
}
String z =  TestObj.b;
执行这段代码只会输出 2 ,因为 并不会触发 inteface 的父接口初始化

类与类加载器

类加载器虽然只用于类的加载动作,但是它在java程序中起到的作用远远不限制于类加载阶段,对于任意一个类,都需要由加载这个类的类加载器和类本身一同确认这个类在jvm中的唯一性,也就是说,同一个类文件,如果被不同的类加载器加载,那么这两个类肯定不相等,比如调用 instandof 关键字判断

双亲委派模型

从 jvm 的角度来看,类加载器只存在2种类型,一种是 (bootstarp ClassLoader) 这个是启动类加载器,使用c++语言实现,是虚拟机自身的一部分,另一种就是其他的类加载器,这里借用断水流大师兄的话就是说,只有空手道部门,或者其他部门,bootstarp就是空手道部门,剩下的类加载器就是其他部门,这些其他类加载器由java语言实现,集成抽象类,java.lang.classLoader
常用的3种类加载器

  • 1启动类加载器(bootstarap ClassLoader)
    前面已经说过,这个加载器是空手道部分,属于jvm的一部分,由c++实现,作用是负责将存放在<JAVA_HOME>/lib中的,或者被 -Xbootclasspath 指定的路径中,并且被虚拟机识别的(按照文件名识别,比如rt.jar,名字不符合的类库,即使放在lib目录下也不会被加载)

  • 2扩展类加载器(extension classloader)
    这个类加载器,负责加载 <JAVA_HOME>/lib/ext目录中的,或者是被 java.ext.dir系统变量所指定的路径中的类库,开发者可以直接使用该类加载器

  • 3应用程序类加载器(application classLoader)
    一般情况下我们称他为系统类加载器,它负责加载用户类路径 classpath上指定的类库,开发者可以直接使用这个类加载器,如果没有自定义类加载器,这个类加载器就是默认类加载器

  • 4自定义类加载器
    指我们开发者 extends ClassLoader 自己实现的类加载器
    * 双亲委派的工作流程
    如上图,双亲委派的工作流程是,如果一个类加载器收到了类加载的请求,那么它不会自己尝试加载这个类,而是先委托它的父类加载器去加载这个类,每一层的类加载器都是如此,只有父类加载器反馈无法完成这个加载请求的时候(它的搜索范围,没有找到对应的类),子类加载器才会自己去加载
    使用双亲委派模型来组织类加载器之间的关系,有一个显而易见的好处就是java的类也跟着类加载器有了层次关系,比如java.lang.Object,它存放在rt.jar之中,不管是哪个类需要加载这个类,都会最终委派到最顶级的类加载器中,这样就保证了不管在哪个类加载器下面,这个类都是同一个类。

  • 破坏双亲委派模型
    双亲委派模型并不是一个强制性的约束模型,而是java推荐给开发者的一种模型,java中的大部分类加载器都是遵循着这个模型,但是也有例外, 到现在为止,双亲委派模型出现过3次较大规模的破坏

第一次被破坏
发生在双亲委派模型出现之前,双亲委派模型是jdk1,2之后引入的,为了兼容之前的版本,java.lang.ClassLoader 增加了一个新的protected方法findClass() 在此之前,继承classloader的目的无非就是为了重写loadclass方法,1.2之后已经不提倡覆盖loadClass方法,应当写到findClass方法之中,如果父类加载器加载失败,则自动会调用自己的findClass方法,这样就保证写出来的类加载器是符合双亲委派模型的
第二次破坏
第二次破坏是由这个模型自身的缺陷引起的,双亲委派模型很好的解决了基础类在各个类加载器中的统一问题,理想状态下都是由用户调用基础类的代码,但如果基础类需要调用用户编写的代码呢,由于父类加载器中并不存在子类加载器加载的的类文件,为了解决这个问题,java开发团队只好引入了一个不太优雅的设计,线程上线文类加载器, 这个类加载器可以通过java.lang.Thread的setContextClassLoaser()方法进行设置,如果创建线程时未设置,则从父线程中继承一个,如果应用程序全局范围内都没有设置过得话,那么就是默认的 应用程序类加载器,有了线程上下文类加载器,在执行基类的代码时,就可以得到当前应用程序的类加载器,因为用户的代码都是由应用程序类加载器加载,所以就可以通过反射或者其他的办法进行调用
第三层次破坏
第三次破坏是当前一些热门的词 “热替换”,“热部署”,动态替换,已经加载的类文件,这种不太熟悉,不做介绍,详情可参考其他文章。

java类加载机制?双亲委派模型有可能被破坏吗相关推荐

  1. 面向对象回顾(静态变量、类加载机制/双亲委派模型、Object类的方法、类和对象区别)

    1. 静态变量存在什么位置? 方法区 2. 类加载机制,双亲委派模型,好处是什么? 某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务, ...

  2. java类加载和双亲委派模型浅说

    本文目录 前言 一.类加载器 1.1 类加载机制的基本特征 1.2 类加载的分类 1.3 类加载器 A.启动类加载器(引导类加载器,Bootstrap ClassLoader) B.扩展类加载器(Ex ...

  3. 由源码深入Java类加载器(双亲委派模型)

    JVM类加载器 JVM主要有以下几种类加载器: 引导类加载器 主要加载JVM运行核心类库,位于JRE的lib目录下,如rt.jar中的类. 扩展类加载器 主要加载JVM中扩展类,位于JRE的ext目录 ...

  4. Java类加载机制双亲委派机制

    关键知识点提炼: 类的唯一性:类的实例= 类加载器 ➕全限定类名 (扩展pandora容器隔离原理-类加载器隔离) 类加载过程:家(加)宴(验)准备了西(析)式菜. 加载-验证-准备-解析-初始化 双 ...

  5. 看完吊打面试官!java类加载机制双亲委派

    前言 周末花了2天时间学习了额RabbitMQ,总结了最核心的知识点,带大家快速掌握RabbitMQ,整理不易希望帮忙点赞,转发,分享下,谢谢 阿里的人才画像 其实最近两年自己一直在做面试官,也面试过 ...

  6. 类加载机制-双亲委派,破坏双亲委派--这一篇全了解

    概述 概念 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接时候用的Java类型. 类的生命周期 类从被加载到虚拟机内存中开始,到卸载出内存 ...

  7. JVM成神之路-类加载机制-双亲委派,破坏双亲委派

    概述 概念 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接时候用的Java类型. 类的生命周期 类从被加载到虚拟机内存中开始,到卸载出内存 ...

  8. 类加载机制--双亲委派

    类加载机制--双亲委派  BootsTrap  ------ %JAVAHOME%/lib下面的jar | | Extension ------ %JAVAHOME%/lib/ext 路径下的jar ...

  9. java类加载机制为什么双亲委派_[五]类加载机制双亲委派机制 底层代码实现原理 源码分析 java类加载双亲委派机制是如何实现的...

    Launcher启动类 本文是双亲委派机制的源码分析部分,类加载机制中的双亲委派模型对于jvm的稳定运行是非常重要的不过源码其实比较简单,接下来简单介绍一下我们先从启动类说起有一个Launcher类 ...

  10. 【Java 虚拟机原理】Android 类加载机制 ( 双亲委派机制 | BootClassLoader | PathClassLoader | DexClassLoader )

    文章目录 一.Android 类加载机制 二.双亲委派机制 一.Android 类加载机制 Android 中的类加载 使用了 双亲委派 机制 , 如下图所示 : 在 Android 中提供了 333 ...

最新文章

  1. delphi 企业微信消息机器人_简单用VBS调用企业微信机器人发定时消息的方法
  2. 华为终于放出方舟编译器源代码!开源平台同步亮相,网友:硬核项目
  3. No changes detected
  4. cdi 作用 spring_什么是CDI,它与@EJB和Spring有什么关系?
  5. 近7万新冠域名一半是钓鱼网站?以色列老牌安全厂商Check Point推出全端保护新战略
  6. pytion3--用户定义的迭代器
  7. 腾讯广告算法大赛 | 第二周周冠军心得分享
  8. php获取服务器类型,php获取服务器操作系统类型的方法
  9. 20个经典模拟电路(详细图文)
  10. html实现点击直接下载文件-前端教程
  11. C专家编程(学习笔记)_第10章 再论指针
  12. fewX(fsod)的预测代码编写--detectron2框架的一般见解(1)
  13. 转:“有活吗?我们什么都干!”稻盛和夫这样带企业穿越萧条
  14. 职场必杀技之职场英语
  15. 进击的UI-----------------UITableView(表视图)
  16. 入行数据分析要知道什么是独立性检验拟合优度检验
  17. 科技公司产品经理和技术总监哪个更重要?
  18. android面试!一线互联网移动架构师设计思想解读开源框架!复习指南
  19. Xilinx FPGA----ChipScope(硬件仿真 Core inserter方法)
  20. 程序员软件开发 面试常见问题

热门文章

  1. Problem L: 数羊————思维不严谨
  2. 线性代数【18】点积和对偶性
  3. 史丰收速算|2014年蓝桥杯B组题解析第四题-fishers
  4. c语言 北京时间转换utc时间_UTC时间与北京时间相互转换
  5. asp.net发邮件
  6. 用Python进行web开发需要学习什么?
  7. 导弹打飞机问题(贪心算法)
  8. 三刺激值计算公式_三刺激值及对应的xyU'V'
  9. 利用计算机指令清理垃圾,系统运维---教你用dos命令清除系统垃圾的快速方法
  10. hp 服务器 阵列卡信息导入,HP Proliant系列服务器 配置阵列卡过程.doc