先来说一下类的加载方式,一个类被加载出来有两种方式,分别是显示加载和隐式加载:
- 显示加载:loadClass和forName等
- 隐式加载:new
隐式加载是通过new一个class来获得类的实例相对于显示加载更加好的地方在于它可以直接调用有参构造。
显示调用原则不是很简单当获取到class对象之后需要调用class的new Instance()方法才能获取到类的实例,调用new Instance()不能进行参数的填充。
接下来来说一下loadClass和forName的区别。。
当调用这两个方法时候都可以知道类对应的全部属性和方法,对于一个任意的对象都可以调用其属性和方法。
从类的装载过程来解决这个问题:
装载: 一个class对象的生成过程,class对象的装载一共分为三步:
- 加载
ClassLoader的loadClass方法将类的字节码加载到内存中,这些类型数据转换成运行时方法区的类型数据,运行时候会生成一个.class,成为访问当前这个java文件的入口。
- 链接
检验.class文件是否通过编译,并且同时检查安全性;准备为类变量分配存储空间并设置类变量的初始值;解析JVM将常量池内的符号引用转换为直接引用。
- 初始化
执行类变量相关的赋值和静态的代码块。
Class.forName得到的class是初始化完成的,ClassLoader.loadClass得到的class只是完成了加载过程其余的步骤还没有完成。
编写一个实体类包含静态方法块:
public class Person {
private String name;
public void sayHello(String sentence){
System.out.println(sentence + " " + name);
}
private String hello(String flag){
return "Hello" + " " + flag;
}
static {
System.out.println("I love you forever");
}
}
执行这段代码,发现使用loadClass的结果只是完成第一步:检查编译是否能够通过,结果就是没有输出静态代码块中的内容。
使用Class.forName()加载实体类,完成初始化步骤静态代码块中的内容会输出: