什么是类加载?
java程序运行前,要经过编译即.java=>.class文件。运行的时候java进程(JVM)就会读取对应的.class文件,并解析内容,在内存中构造出类对象并进行初始化(类对象就是描述这个类有哪些属性,哪些方法,继承哪些类,实现哪些接口)
类加载的过程
- 加载
这里的加载(loading)和类加载(class loading)不同,加载是类加载的一个阶段。主要任务是找到.class文件,读取文件内容,并且按照.class规范格式来解析
- 连接
- 验证
检查当前.class文件中的内容格式是否符合规范要求。
- 准备
给类里的静态变量分配内存空间并设置类变量初始值。
- 解析
将常量池内的符号引用(占位符)替换成直接引用(内存地址),也就是初始化常量的过程。
比如String s = "hello";在类加载之前,"hello"这个字符串常量没有分配内存空间(类加载完成后才有内存空间)无法保存字符串常量的真实地址,只能先使用占位符标记一下,等真正给"hello"分配过内存后,再用真正的地址替代之前的占位符。
- 初始化
针对类进行初始化,初始化静态成员,执行静态代码块,并且加载父类。
何时触发类加载
使用到一个类的时候就会触发类加载,并不一定程序一启动就加载,第一次使用到这个类才会加载。
1.创建这个类的实例 2. 使用这个类的静态属性/静态方法 3.使用这个类的子类
双亲委派模型
按照什么样的规则在目录中查找.class文件
在了解这个模型之前要先了解3个类加载器
Bootstrap ClassLoader负责加载标准库中的类
Extension ClassLoader负责加载JVM扩展的库的类
Application ClassLoader负责加载自己项目中自定义类
这三个类加载器相互配合的工作流程
上述三个类存在父子关系
进行类加载的时候,如Java.lang.Thread是从Application ClassLoader开始
某个类加载器开始加载的时候,不会立即扫描自己负责的路径,而是先把任务交给父亲来处理
如果到了Bootstrap ClassLoader,已经是最上层了,只能自己加载
如果父亲没找到这个类,就交给儿子,继续加载
如果一直找到最下面Application ClassLoader也没找到,就会抛出ClassNotFund异常
双亲委任模型的好处
如果程序员的自定义类的全限定名和标准库的类冲突了,如自定义类也叫做java.lang.Thread,会一直向上传递到Bootstrap ClassLoader可以保证可以加载到标准库的类,防止代码加载出错