我们都知道任何程序都需要加载到内存才能与CPU进行交流
字节码.class文件同样需要加载到内存中, 才可以实例化类, 兵马未动粮草先行, ClassLoader正是准备粮草的先行军, 它的使命就是提前加载.class类文件到内存中, 在类加载时, 使用的是Parents Delegation Model, 称为: 双亲委派模型
java的类加载是一个运行时核心基础设施模块, 主要是在启动时进行类的Load, Link和Init, 即为加载, 链接, 初始化
-
第一步, 加载(Load)阶段读取类文件产生二进制流, 并转化为特定的数据结构, 初步校验常量池, 文件长度,
是否有父类等,然后创建对应类的java.lang.Class实列 -
第二步, 链接(Link)阶段包括验证, 准备, 解析三个步骤, 验证是更详细的校验, 比如final是否合规, 类型是否正确,
静态变量是否合理等, 准备阶段是为静态变量分配内存, 并设定默认值, 解析类和方法确保类与类之间的相互引用正确性,完成内存结构布局 -
第三步, 初始化(Init)阶段执行类构造器方法, 如果赋值运算是通过其他类的静态方法来完成的,
那么会马上解析另外一个类, 在虚拟机栈中执行完毕后通过返回值进行赋值
java类加载过程如图:
理解: 将.java源文件编译成字节码, 然后进行类加载(类加载又分为三步加载, 链接, 初始化, 链接又分为三步: 验证, 准备, 解析), 加载完之后,或者直接解释执行, 让CUP读取, 或者让JIT编译之后转为机器码再让CUP读取
类加载是一个将.class字节码文件实列化成Class对象并进行相关初始化的过程, 在这个过程中, JVM会初始化继承树上还没有被初始化过的所有父类, 并且会执行这个链路上所有未执行过的静态代码块, 静态变量赋值语句等, 某些类在使用时, 也可以按需有类加载器进行加载
全小写的class是关键字, 用来定义类, 而首字母大写的Class, 它是class的类
- Class类下的newInstance()在JDK9中已经置为过时,
使用getDeclaredConstructor().newInstance()的方式, new与newInstance的区别,
new是强类型校验, 可以调用任何构造方法, 在使用new操作的时候, 这个类可以没有被加载过,
而Class类下的newInstance是弱类型, 只能调用无参构造方法, 如果没有默认构造方法,
就抛出InstantiationException异常, 如果此构造方法没有权限访问,
则抛出IllegalAccessException异常, java通过类加载器把类的实现与类的定义进行解耦, 所以是实现面向接口编程,依赖倒置的必然选择
private成员在类外是否可以修改?
答: 可以的, 通过setAccessible(true)操作, 即可以使用大写Class类的set方法修改其值
如下代码:
public class Test{
private static Class<Two> two = Two.class;
public static void main(String[] args) throws Exception{
//通过newInstance方法创建Two对象
Two twoObject = two.newInstance();
//通过two这个大写的Class对象, 获取私有成员属性对象Field
Field privateFieldInTwo = two.getDeclaredField("inner");
//设置私有对象可以访问和修改
privateFieldInTwo.setAccessible(true);
//修改私有对象的值
privateFieldInTwo.set(twoObject,"Hello Word");
}
}
class Two{
private String inner="time flies";
public String getInner(){
return inner;
}
}
类加载器类似于原始部落结构, 存在权利等级制度, 最高的一层是家族中威望最高的Bootstrap, 它是在JVM启动时创建的, 通常由与操作系统相关的本地代码实现, 是最根基的类加载器, 负责装载最核心的java类, 比如Object, System, String等
第二层是在JDK9版本中, 称为Platform ClassLoader, 即平台类加载器, 用以加载一些扩展的系统类, 比如XML, 加密, 压缩相关的功能类等, JDK9之前的加载器是Extension ClassLoader,
第三层是Application ClassLoader的应用类加载器, 主要是加载用户定义的CLASSPATH路径下的类, 第二, 三层类加载器为java语言实现, 用户也可以自定义类加载器
类加载器具有等级制度, 但是并非继承关系, 低层次的当前类加载器, 不能覆盖更高层次类加载器已经加载的类
用户在什么情况下需要自定义类加载器?
答:
(1), 隔离加载类
(2), 修改类加载方式
(3), 扩展加载源
(4), 防止源码泄漏