1 类加载机制概念是什么?
JVM 把描述类的数据从 Class 文件加载到内存, 并对数据进行校验转换解析和初始化, 最终形成可以被虚拟机直接使用的 Java 类型这就是类加载机制
2 类字节码有哪几部分内容组成?
Class 文件结构中只有两种数据类型:
无符号数: 属于基本的数据类型, 以 u1u2u4u8 分别代表 1248 个字节的无符号数, 可以用来描述数字索引引用数量值或者按照 UTF-8 编码的字符串值;
表: 由多个无符号数或者其他表作为数据项构成的复合数据类型, 所有表都习惯以 "_info" 结尾;
所以, Class 文件本质上就是一张表;
Class 文件结构的内容组成:
魔数: 每个 Class 文件的前 4 个字节, JAVA 语言魔数: CAFEBABE,16 进制数, 唯一左右就是确认文件是否是一个被虚拟机接受的 Class 文件;
Class 文件版本: Class 文件第 56 个字节是次版本号, 78 个字节是主版本号;
常量池: 从第 9 个字节开始, 主要存放两大类常量:(1)字面量;(2)符号引用;
访问标志: 紧跟常量池之后的两个字节代表访问标志, 代表类或接口的层次信息;
类索引父类索引与接口索引集合: 紧跟访问标志之后的就是类索引父类索引与接口索引, 都是 u2 类型数据, Class 文件中由这三项数据来确定类的继承关系;
字段表集合: 紧接着就是字段表集合, 用于描述接口或类中声明的变量;
方法表集合: 紧接着就是方法表集合, 用于描述接口或类中声明的方法;
3 类加载过程大体分为几步?
4 什么时机会出发类加载?
创建类的实例: 使用 new 关键字实例化对象;
访问类的静态变量: getstatic 或 putstatic, 读取或设置一个类的静态变量(不包括被 final 修饰的静态变量);
访问类的静态方法: invokestatic 调用一个类的静态方法;
使用 java.lang.reflect 进行反射调用: 如, Class.forName("xxxxx");
子类初始化时, 会先初始化父类;
5 被动引用有几种, 被动引用不会触发类初始化?
通过子类引用父类的静态字段, 不会导致子类初始化, 只会初始化父类;
通过数组定义来引用类, 不会触发类的初始化;
常量在编译阶段会存入调用类的常量池中, 本质上并没有直接引用到定义常量的类, 因为不会触发定义常量的类初始化;
6 类加载: 第一步加载阶段具体过程?
通过类的全限定名称获取定义此类的二进制流;
将二进制流静态结构转化为方法区的运行时数据结构;
在内存中生成一个代表这个类的 java.lang.Class 对象对于 HotSpot 虚拟机, Class 对象是存放在方法区里的;
7 类加载: 第二步验证阶段具体过程?
主要作用就是确保 Class 文件的字节流中包含的信息符合当前虚拟机的要求, 并且不会危害虚拟机自身安全;
文件格式验证: 对检查格式版本;
元数据验证: 对字节码进行语义分析;
字节码验证;
符号引用验证;
8 类加载: 第三步准备阶段具体过程?
正式为类变量分配内存, 内存在方法区中进行分配, 类变量是指 static 修饰的变量;
设置类变量的初始值, 这个初始值通常情况下是数据类型的零值, 如: public static int value = 123; 初始值是 0, 不是 123, 赋值 123 动作会在初始化阶段才会执行;
9 类加载: 第四步解析阶段具体过程?
将 Class 文件的常量池内的符号引用替换为直接引用;
10 类加载: 第五步初始化具体过程?
真正开始执行类中定义的 Java 程序代码, 初始化过程就是执行类构造器 () 方法的过程;
()方法会自动收集类中所有类变量 (static) 的赋值动作和静态代码块, 编译器收集顺序由代码出现顺序决定;
()方法与类实例构造函数不同, 虚拟机会保证父类的 () 执行完毕后再执行子类的 () 方法;
12 类加载器有几种, 每种的作用?
根类加载器(Bootstrap ClassLoader): 其负责加载 Java 的核心类, 比如 StringSystem 这些类;
拓展类加载器(Extension ClassLoader): 其负责加载 JRE 的拓展类库;
系统类加载器(System ClassLoader): 其负责加载 CLASSPATH 环境变量所指定的 JAR 包和类路径;
用户类加载器: 用户自定义的加载器, 以类加载器为父类
13 类加载器双亲委托模式是什么及为什么?
双亲委派机制: 如果一个类加载器在接到加载类的请求时, 它首先不会自己尝试去加载这个类, 而是把这个请求任务委托给父类加载器去完成, 依次递归, 如果父类加载器可以完成类加载任务, 就成功返回; 只有父类加载器无法完成此加载任务时, 才自己去加载
Java 类随着加载它的类加载器一起具备了一种带有优先级的层次关系比如, Java 中的 Object 类, 它存放在 rt.jar 之中, 无论哪一个类加载器要加载这个类, 最终都是委派给处于模型最顶端的启动类加载器进行加载, 因此 Object 在各种类加载环境中都是同一个类如果不采用双亲委派模型, 那么由各个类加载器自己取加载的话, 那么系统中会存在多种不同的 Object 类
来源: https://juejin.im/post/5ab1e65cf265da23923637c9