文章目录
- 引言
- 类加载机制
- 知识点复习
- 类的生命周期
- 1、加载
- 2、连接——验证
- 3、连接——准备
- 4、连接——解析
- 5、初始化
- 类加载器和类加载机制
- 类加载器
- 类加载机制——双亲委派模型
- 面试题整理
- 1、类加载是什么
- 2、类加载的过程是什么
- 3、有哪些类加载器?
- 4、双亲委派模型是什么
- 5、如何判断两个类是否相等
- 总结
引言
- 在百度提前批面试中,第一个章节的问题关于类加载的相关知识点,忘得一干二净,这里整理一下!
- 主要是类加载的过程还有双亲委派模型
- 整理也是按照之前的惯例,先是基本的知识点,然后就是对应的面试题整理
类加载机制
知识点复习
类的生命周期
- 类的生命周期如下,除了最后的使用和卸载,其他的基本上都很重要
- 加载
- 连接
- 验证
- 准备
- 解析
- 初始化
- 使用
- 卸载
- 特征
- 上述生命周期是按顺序开始,但是并不是按顺序完成
- 通常一个阶段执行的过程中调用和激活另外一个阶段
1、加载
- 类加载器主要完成三件事,分别是
- 找到在哪里:通过一个类的全限定名,来获取定义此类的二进制字节流
- 加载到方法区:将字节流所代表的静态存储结构转化为方法区的运行时数据结构
- 创造对象提供入口:在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口
2、连接——验证
- 目的
- 检查Class字节流,确保这个字节流是符合要求的,不会有安全性问题
- 验证内容
- 文件格式验证:版本号,还有开头的符号
- 元数据验证:语义分析,是否符合Java语言规范,继承抽象类的类是否实现抽象方法等
- 字节码验证:语义分析,数据流和控制流分析,程序是否合法或者符合逻辑等
- 符号引用验证:对类中所引用的信息的匹配性校验(常量池中的各种符号引用)
- 根据符号引用描述的名字能否找到对应的类
- 符号引用的对象是否可被当前类访问
从文件格式,到语法规范,再到所引用对象
3、连接——准备
- 目的
- 为类的**静态变量(static修饰的)**分配内存,初始化为默认值,如果使用了final修饰,则会给初始值
- 注意
- 只给类变量分配内存,不给实例变量分配内存
- 使用final修饰的static变量,会直接赋初始值,不会默认值
4、连接——解析
- 目的
- 将常量池中符号引用替换为直接引用
- 符号引用
- 是一组符号来描述所引用的目标,相当于是相对引用
- 直接引用
- 直接指向目标的指针、相对偏移量、或者一个能定位到目标的句柄。
- 符号引用
- 将常量池中符号引用替换为直接引用
5、初始化
-
目的
- 为类的静态变量赋初始值,不同于之前的准备,是给静态变量赋默认值
-
初始化方式
- 声明类变量指定初始值
- 使用静态代码块指定初始值
-
步骤
- 如果这个类没有被加载或者连接,则程序先加载和连接这个类
- 如果该类的直接父类没有被初始化,则先初始化其直接父类
- 如果类中有这些初始化语句,则系统依次执行这些初始化语句
-
类初始化的时机
-
只有当类主动使用的时候,才会导致类的初始化,具体时机如下
- 调用对应类的静态方法
- 初始化某一个类的子类,父类也会被初始化
- 创建类的实例
- 使用反射
类加载器和类加载机制
类加载器
-
类唯一性的确立
- 一个类必须由加载他的类加载器和这个类本身一块共同确立其唯一性
-
具体应用
- 同一个Class文件加载的对象,可能调用getClass返回的都是同一个名字,但是如果类的加载器不同,instanceof返回的结果也是false
三个类加载器
-
启动类加载器
- 负责加载Java核心类库,是所有类加载器的顶层
- 使用本地代码实现,依赖于操作系统的本地代码C++或者C
- 无法通过Java代码直接获取到启动类加载器的实例
- 核心类库
- 运行时类库:rt.jar
- 基础类:String、Object、System
-
扩展类加载器
- 负责加载标准扩展目录中的类和资源。
- 使用Java代码实现,可以获取对应对象()了解
ClassLoader extClassLoader = appClassLoader.getParent();System.out.println("Extension ClassLoader: " + extClassLoader);
- 应用类加载器
- 是用户自定义类和第三方库的默认类加载器,加载应用程序类路径下的类库
ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();
System.out.println("Application ClassLoader: " + appClassLoader);
类加载机制——双亲委派模型
- 定义
- 如果一个类加载器的收到了类加载的请求,首先不会尝试自己去加载这个类,而是把这个请求委托给父类加载器去完成。
- 所有的类加载请求,都应该传递到最顶层的启动类加载器中。
- 只有当父加载器反馈自己无法完成这个加载请求时,子加载器才会尝试自己去完成加载
- 如果一个类加载器的收到了类加载的请求,首先不会尝试自己去加载这个类,而是把这个请求委托给父类加载器去完成。
典型应用
- 能不能自定义类加载器加载String类?
- 不行
- 不行
面试题整理
1、类加载是什么
-
类加载就是把Class文件中的类信息加载到虚拟机中,并形成可以被虚拟机使用的Java类型是类加载机制。
-
Java的运行期间动态加载和连接:Java中类型的加载、连接和初始化是在运行期间完成的,实现了Java的动态扩展性。
-
一个类从加载到虚拟机再到卸载需要经历如下流程
- 加载
- 连接
- 验证
- 准备
- 解析
- 初始化
- 使用
- 卸载
2、类加载的过程是什么
-
加载
- 通过类的全限定名,找到对应二进制字节流文件
- 将二进制字节流文件中的类的静态存储结构加载到方法区中,转为运行时数据。
- 在堆区创建对应的Class对象,作为访问类信息的入口
-
验证
- 检查字节流,防止载入错误或者恶意的字节流文件,导致JVM崩溃
- 验证流程:文本格式验证、符号引用验证、元数据验证、字节码验证等
-
准备
- 为类的静态变量分配内存,并赋默认值或者常量(final static修饰的)
-
解析
- 将符号引用替换为直接引用,能够直接指向引用对象句柄或者指针等
-
初始化
- 直到该阶段,JVM才开始执行类中编写的代码,根据程序员的编码对类的静态变量去赋值,
- 执行类构造方法中的clinit方法
3、有哪些类加载器?
- 有三层类加载器
启动类加载器
- 在JVM启动时创建,加载最核心的类,如Object、String等,使用本地代码,由操作系统实现
扩展类加载器
- 扩展类加载器,复杂加载一些扩展的系统类,比如XML、加密、网络编程等功能类。
应用类加载器
- 系统类加载器,是加载用户类路径上的类库,直接在代码中使用
- 如果没有自定义类加载器,一般情况下,默认类加载器就是应用类加载器。
- 自定义类加载器是通过继承ClassLoader并重写findclass实现的
4、双亲委派模型是什么
-
类加载器具有等级制度,但不是继承关系,分层但非继承,以组合的方式,复用父加载器的功能。
- 除了顶层的启动类加载器之外,其余类加载器都要用自己的父加载器
-
具体原理
- 一个类加载器收到类加载请求,不会自己去加载,而是把请求委派给父加载器。以此类推,最后所有请求都会到启动类加载器。
- 只有当父类加载器无法完成式,子类加载器才会去尝试加载
5、如何判断两个类是否相等
- 确定一个类需要类自身的信息还有对应的加载器,共同确定唯一性。
- 两个类只有由同一个类加载器加载才有比较意义
- 如果不是同一个类加载器加载,即使来在同一个Class文件,两个类也不相等。
总结
- 又攻克了一个难关,好好背一下,至少保证了以后在遇到类似的题目,基本上都能过了!
- 今天本来是想看完垃圾回收机制的,但是晚上腰太疼了,就去推拿了,然后出去吃了点东西,回来的比较晚,剩下两个半小时,要把昨天的面经整理好的,就不看垃圾回收机制了!明天做个笔试,应该也不会刷题了,后续要出去旅游,请假三天!回来接着学!