目录
一、反射
反射机制是java实现动态语言的关键,也就是哦天哪故宫反射实现类动态加载
1、静态加载
编译的时候加载相关的类,如果没有则报错,依赖性太强
2、动态加载
运行时加载需要的类,如果运行的时候,不用该类,即使不存在也不报错,降低了依赖性
二、类加载的时机
- 当创建对象的时候
- 当子类被加载的时候,会先加载父类--父类的初始化
- 当调用类中的静态成员和静态方法(注意调用 static final 不会初始化类,底层做了优化)
- 通过反射获取类对象的时候
三、类加载的流程图
- 将Java源码通过javac编译成字节码文件
- java运行字节码文件的时候,进行类的加载,类加载的三个阶段为 加载 连接 初始化
- 最后类加载完毕后,将在方法区中创建类的字节码的二进制数据,在堆中创建类的Class类对象
四、类加载的三个阶段的详细解释
1.1 加载
jvm在该阶段主要是将字节码从不同的数据源(可能是class文件,也可能是jar包,甚至是网络)转换为二进制字节流加载到内存,并生成一个代表该类的Class类对象
1.2 连接
1、验证
- 确保class文件的字节流中包含的信息是否符合虚拟机的要求,并且不会危害虚拟机自身的安全
- 主要包括 文件格式的验证(是否以OXcafe babe开头的)、元数据验证、字节码验证和符号引用的验证
- 可以考虑使用-Xverify:none参数来关闭大部分的类验证措施,缩短虚拟机加载的时间
2、准备
Jvm会在该阶段对静态变量,分配好内存并进行初始化。 对静态常量分配好内存,直接进行赋值。这些变量 常量所使用的内存都是在方法区中进行分配的
非静态变量,这个时候不进行处理
3、解析
虚拟机将常量池的符号引用替换为直接引用的过程
1.3 初始化
- 到初始化节点,才真正开始执行类中定义的java程序diamante,此阶段是执行<clinit>()方法的过程
- <clinit>()方法是由编译器按照语句在源文件的先后顺序,依次自动收集类中的所以静态变量的赋值和静态代码块中的语句进行合并
- 虚拟机保证了一个类的<clinit>()方法在多线程的环境中被正确的加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的<clinit>(),直到获得线程执行完<clinit>()方法完毕