1.类加载子系统
一、内存图总体
二、类加载子系统
2.1 类加载子系统三个环节:加载,链接、初始化
补充 _反编译 指令 : javap -v xxx.class
将 .class 文件加载到内存的三个环节: 加载 链接 初始化
ClassLoader 只负责 加载 calss文件 ,至于能不能执行 ,由 执行引擎 决定
2.1.1 第一个环节 :Loading 阶段(加载)
1.通过 一个类 的全限定名 获取此类的 二进制字节流
2.将
3.在内存中 生成 一个 大的 Class 类的 对象 ,作为类的访问入口
2.1.2 第二个环节 :Linking 阶段(链接)
链接阶段 分为 三个阶段 : 验证(Verify)、准备(Prepare) 、解析(Resolve)
验证: 验证是不是 class文件 , 二进制开头:CA FE BA BE(咖啡baby)
准备:为变量分配内存,以及设置默认值 ,即 0,null,false,/u000(char)
final编译的时候就分配值了,准备阶段 显示初始化(确定一下)
这里不会为 new 的对象分配内存,因为 还在 加载 类 的阶段
解析:将常量池的 符号引用 转为 直接引用 (未了解)(动态链接相关)
2.1.3 第三个环节: Initialization 阶段(初始化)
初始化阶段就是 执行 类构造器方法<client>()方法和<Init>()方法
<client>():
javac 编译器 自动收集 类中 的 所有 全局变量(static、类变量)和 静态代码块 的赋值动作 而来
按照顺序执行 赋值的 (是 赋值 ,声明 已经在 第二个环节(Linking的 准备环节)已经声明过 了)
<Init>():
执行构造器,一定是 先执行父类 在执行子类的
子类被加载之前,一定是先加载 父类
如下图, 输出语句用到了 SON 首先会 加载 SON的父类 然后加载子类
2.2 类的加载器分类
类加载器分类:
1.引导类加载器(BootStrap ClassLoader) C和C++(可多继承)实现的
2.拓展类加载器(Ext ClassLoader) java实现的
3.系统类加载器(App(System) ClassLoader)) java实现的
引导类加载器 负责 加载java的核心类库 JDK,出于安全的考虑,引导类加载器只加载包名为:java、javax、sun开头的
拓展类加载器 负责 加载 jre\lib\ext 子目录的类库,如果用户创建的 jar包放进去,那么,拓展类加载器 也会 加载 用户的 jar包
系统类加载器 负责 用户自定义类
2.2 后续 、拓展:用户自定义类加载器
为什么要自定义要类加载器:
1.隔离 加载类( 类名啥的 都相同,需要隔离)
2.修改类的加载方式()
3.扩展加载源()
4.防止源码泄露(很容易被篡改,可以对字节码以 自己 的方式进行加密,执行解密需要 自定义类加载器 解密)
怎么做:
1.extend ClassLoader
2.1.2之前 ,需要重写一个 loadclass()方法
1.2之后,建议把自定义的逻辑卸载 findClass()方法中,不需要重写loadClass()了
3.如果没有太过于复杂的要求,可以直接继承URLClassLoader,使代码更简洁
2.3 双亲委派机制
先不加载,先让父亲去加载,递归,直到引导类,
如果 引导类加载器 能完成加载任务,那就加载,不会向下委托了。
如果不能完成加载任务,然后 再向下 委托,直到 能完成任务。
某些接口由 引导类加载的,那么 实现类 由 系统类(第三层) 加载器 加载的
优势:
1.避免类的重复加载
2.保证程序的安全,防止核心类库被篡改( 沙箱安全机制 ) , 防止自己的类和核心类库jdk冲突
判断JVM中两个类是否为同一个类:
1.包名和类名一样
2.加载此类的ClassLoader必须是一样的