ClassLoader主要作用 :将.class后缀的字节码文件从硬盘上装载到内存中 ;
1.类加载器深入剖析
Java虚拟机与程序的生命周期 :
当我们执行一个java程序的时候 , 会启动一个JVM进程 , 当程序执行完之后 , JVM进程就消亡了;
在如下情况下JVM将结束声明周期 :
- System.exit(int)方法 , 当执行这个方法的时候 , 虚拟机会退出 ; 这个方法传入一个整形参数 , 这个参数是状态吗: 如果这个整形是 0 的话 , 就是正常退出 , 如果不是0的话 , 就是异常退出 ;
- 程序正常结束;
- 程序执行过程中 ,遇到了异常或错误 , 而异常终止 : 如果我们在程序中出现了异常 , 而不去处理 , 会将异常一直抛给main函数 ,main函数会将异常抛给JVM , JVM如果处理不了异常 , JVM就会异常退出 ;
- 由于操作系统出现错误导致JVM进程终止 : JVM所依赖的平台出现错误 , 导致JVM终止 ;
2.类的加载,连接和初始化
- 加载 :查找并加载类的二进制数据 , 将class字节码文件加载到内存中 ;
- 连接 :
-验证 : 确保被加载的类的正确性 , 使用javac编译工具生成的字节码文件能通过验证 , 如果不是由javac编译生成的字节码文件 ,如果自己生成的字节码文件不符合JVM虚拟机对字节码文件的要求的话 , 可能会出现验证通不过的情况 ; 比如说随便拿一个文件 , 将后缀名直接修改为.class , 这样的字节码文件肯定不合法;
-准备 : 为类的静态变量分配内存 , 并将其初始化为默认值;
-解析 : 把类中的符号引用转为直接引用 ;- 初始化 :为类的静态变量赋予正确的初始值(正确的值指的是用户赋的值) ;
- -好像这个与连接阶段的准备有些重复 , 在连接的准备阶段只是赋予初始变量 , 如果用户给这个变量赋了初始值 ,那么这个变量在连接的准备阶段仍然会赋予初始值 ;
-在这个阶段 , 才会真正的将初始值赋给静态变量 ;
Java程序对类的使用方式有 主动使用 和被动使用 ;
所有的JVM实现 , 必须在每个类或者接口 , 被java程序 “首次主动使用” 时才初始化他们;
主动使用 :
- 创建类的实例 ;
- 访问某个类或接口的静态变量 , 或者对该静态变量赋值 ;
- 调用类的静态方法 ;
- 反射 : Class.forName(“类名”) ;
- 初始化一个类的子类 , 看做对父类的主动使用 ;
- java虚拟机启动的时候 , 被标明启动类的类 , 即包含main方法的类 , 程序的入口;
除了上面6种主动使用之外 , 其它的情况均为被动使用 , 其它情况都不会执行第三步初始化 ;
3.类的加载
(1)概念
- 类的加载 : 指的是将类的.class文件中的二进制数据读入到内存中 , 将其放在运行时数据区的方法区内 , 然后再堆区创建一个java.lang.Class对象 , 用来封装类在方法区内的数据结构 ;
- 反射 : 反射就是跟句堆区的字节码文件 , 获取方法去的数据结构 ;
- 解析 : Class对象是由JVM自己创建的 , 所有的对象都是经过Class对象创建 , 这个Class对象是反射的入口, 通过Class对象 , 可以关联到目标class字节码文件的内部结构 ;
所有的类对应的Class对象都是唯一的一个 , 这个类是由JVM进行创建的 , 并且只有JVM才会创建Class对象;
类加载的最终产品是位于堆区中的Class对象 ,Class对象封装了类在方法区内的数据结构 , 并且向Java程序员提供了访问方法区内的数据结构的接口(反射用的接口) ;
(2)加载.class文件的方式
从本地系统中直接加载 : 编译好的.class字节码文件直接从硬盘中加载 ;
通过网络下载.class文件 : 将class字节码文件放在网络空间中 , 使用URLClassLoader来加载在网络上的.class字节码文件 , 使用默认的父亲委托机制加载字节码文件 ;
从zip ,jar 等压缩文件中加载字节码文件 : 在开发的时候 , 导入jar包 , 就是这种方式 ;
从专有的数据库中提取字节码文件 ;
将java源文件动态编译为字节码文件 ;
(3)类加载器
l Java虚拟机自带的类加载器 :
-根类加载器 ( Bootstrap ): 是C++写的 , 程序员无法再方法获取到的是一个null值 ;