类加载子系统的作用:
加载class文件到虚拟机内部至于 能否运行看执行引擎
加载的类的信息存放在方法区(即堆逻辑上的元空间永久代)
类加载子系统
classLoader的作用
.class文件即类的信息加载到方法区作为 元数据模板
.class到jvm再到成为元数据模板需要一个搬运工就是classloader
类加载过程
加载------链接(验证 准备 解析)------初始化
加载阶段:
1.通过全限定名获取定义此类的二进制字节流
2.将这个二进制字节流代表的静态存储结构转换成方法区的运行时数据结构
3. 在方法区中创建一个java.lang.Class对象,作为方法区访问这个类的各种数据方法的入口
链接阶段:
1.验证
验证字节码文件的格式,确保文件的安全性
2.准备
对静态变量分配内存,并赋值为初始值
不会对实例变量进行分配初始化
对final修饰的常量因为final在编译的时候就分配了默认值,准备阶段会显示的初始化
public class HelloApp { private static int a = 1; public static void main(String[] args) { System.out.println(a); } }在准备阶段为a分配内存并赋值为初始值0但不是1,在实例化阶段才会赋值为1.
3.解析
将符号引用变为直接引用
在编译阶段,虚拟机并不知道引用类的地址,所以先用符号替代着,到了解析阶段就会把这个符号变成真正的地址。
初始化阶段
1.初始化阶段就是执行类构造方法 clinit
2.clinit不需要写,它时收集了静态变量的赋值动作和静态代码块构成的,也就是说只要声明了静态变量就会有clinit
3.clinit时类构造方法 init时构造方法
4.如果有父类会先执行父类的clinit再执行子类的clinit
在准备阶段number的值是0
在初始化阶段执行静态变量初始化的时候变成10
在初始化阶段执行静态代码块的时候变成20
number 的声明在后面,但是再static中number=20没有报错,是因为在链接阶段的准备阶段就已经为静态变量number分配内存并赋值初始值0.
可以对number赋值,但是不能调用否则会报错:非法的前向引用!!!!!!
类加载器的分类:
1.引导类加载器bootStrap classLoader 用c++写的不能被java调用以及自定义类加载器
2.特别说明对于自定义类加载器只要是派生与ClassLoader的都叫自定义加载器
3.常见的三种加载器 引导类加载器bootStrap classLoader 加载jre中的rt.jar 扩展类加载器
extention classLoader 加载jre中的lib/ext/*jar appication classLoader系统类加载器应用类加载器
4.加载器之间不是子父类的继承关系
双亲委派机制:
加载一个类的时候,自底向上检查是否加载过这个类从customClassLoader再到APPClassLoader再到EXTClassLoader再到 bootStrap classLoader,如果都哪个类加载器加载过这个类就直接返回,如果都没有,就自顶向下,委派对应的类加载器去对应的加载目录中寻找并加载类。
双亲委派机制的好处:
1.避免重复加载类2.防止java核心API被篡改保护程序安全
例如:不会如加载你自己写的java.lang.String而是会去rt.jar下加载java.lang.String
也不允许自定义java.lang包
三大类加载器
启动类加载器也叫引导类加载器(BootStrap ClassLoader)
1.用c/c++编写,不是java语言编写所以获取不到为null
2.不派生于ClassLoader
3.出于安全考虑,只加载java javax sun开头的包下的类,如java.lang包下的类,这些核心类都被签名不能被替换
扩展类加载器(ExtClassLoader)
1.java语言编写
2.派生于ClassLoader
3.父类加载器是引导类加载器
4.加载JRE/lib/ext/目录的类
应用类加载器(系统类加载器 APPClassLoader)
1.java语言编写
2.派生于ClassLoader
3.父类加载器是扩展类加加载器
4.加载ClassPath下的类
5.程序默认的类加载器,项目中自己写的类由应用类加载器加载
6.ClassLoader.getSystemClassLoader()方法可以获得应用类加载器



