一、JVM类加载过程
JVM将类加载过程分为三个步骤:装载(Load),链接(Link,又分为验证、准备、解析三个步骤)和初始化(Initialize)。
1) 装载:查找并加载类的二进制数据;
2)链接:
验证:校验加载类的正确性;
准备:为类的静态变量分配内存,并将其初始化为默认值;
解析:把类中的符号引用转换为直接引用;
3)初始化:为类的静态变量赋予正确的初始值;
二、JVM加载类的三种方式
1.通过new关键字加载
Object example=new Object();
2.通过ClassLoader实例的loadClass方法加载
ClassLoader loader = ClassLoader.getSystemClassLoader();
Class exampleClass=loader.loadClass("Example");
Object example =exampleClass.newInstance();
3.通过Class.forName加载
Class exampleClass = Class.forName("Example");
Object example =exampleClass.newInstance();
三、加载类三种方式的区别:
1. new关键字加载(第1种)和Class.forName(第2种)加载使用的类加载器是是当前类加载器,即this.getClass.getClassLoader。ClassLoader(第3种)由用户指定类加载器。如果需要在当前类路径以外寻找类,则只能采用ClassLoader方式;
2. 第1种加载方式为静态加载,第2种和第3种加载方式为动态加载,即在运行时加载;
3. 第1、2加载方式将加载类的static内容,第3种方式不加载。因为第1、2种方式会一直执行至初始化(Initialize)过程,而第3种方式执行装载(Load)过程后即终止,不完成链接和初始化过程。
//Class.forName(String className) 源码
public static Class<?> forName(String className) throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
//第二个参数是指Class被loading后是不是必须被初始化。 不初始化就是不执行static的代码即静态代码
//ClassLoader.loadClass(className)实际上调用的是ClassLoader.loadClass(name, false),第二个参数指出Class是否被link。
例如:
//定义Point类
public class Point {
static{
System.out.println("Point静态内容");
}
}
//测试
public class ClassLoaderTest {public static void main(String[] args) {loaderTest();forNameTest();}private static void loaderTest() {System.out.println("===测试ClassLoader====:");ClassLoader loader = ClassLoader.getSystemClassLoader();Class<?> point = null;try {point = loader.loadClass("classLoader.Point");} catch (Exception e) {e.printStackTrace();}}private static void forNameTest() {System.out.println("===测试ForName====:");try {Class<?> point = Class.forName("classLoader.Point");} catch (Exception e) {e.printStackTrace();}}}
//执行结果:
//===测试ClassLoader====:
//===测试ForName====:
//Point静态内容
4. 静态加载方式如果出现类没有找到,将抛出NoClassDefFoundError,Error的子类,而第2、3种方式将抛出ClassNotFoundException检测异常(Checked Exception);