Class类的forName方法是进行反射的核心,它让我们可以随意加载指定的类。Class分别提供了两个forName方法,一个是单参数的,我们只需要把一个表示类的名称的String传进去就可以获得这个类的类型(Class)对象,从而可以进一步进行实例化操作。而另一个三参数的forName方法则是本次的重点。
三个参数分别为String name、boolean initialize以及ClassLoader loader
String name参数指的是类的名称与单参数forName方法的参数是相同意义的。
ClassLoader loader参数指的是类的加载器,一般每个类都有指定的加载器,不可随便选择。
boolean initialize参数指的是在进行类加载时是否执行静态代码块。如果此参数为true时,当我们加载类就会执行静态代码块;如果此参数为false时,当我们加载类时则不会执行静态代码块。通过如下代码我们可以看到效果:
public class Test{
static{
System.out.println("要先生蛋");
}
Test(){
System.out.println("破壳啦~");
}
}
class Test2 {
public static void main(String[] args) {
Class<? extends Object> c = null;
try {
c = Class.forName("Test", true, Test.class.getClassLoader());
//c = Class.forName("Test", false, Test.class.getClassLoader());
System.out.println("****类别准备实体化");
//Object o = c.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
通过实例我们可以发现的确是如此的。
另一方面从这个方法我们不难推测Java的对象实例化过程大致可以分为两步,一步是加载类,一步是生成实例化对象。
在我们执行反射时,首先使用forName方法进行类的加载,再调用newInstance方法进行对象实例化。这样有利于我们进行动态的设计。
而我们一般使用的new关键字,则在进行实例化时把加载与实例化两步顺序执行。
对于ClassLoader loader这个参数,在查询过源码之后发现,如果该参数为null,Java会判断本地系统是否有获取加载器的权限,之所以如果是由于RMI可以通过URL来实例化远程对象,为了系统的安全才做出这样的机制。
在源码中,loader为null时并没有自动生成一个加载器就进行底层调用了,因此猜测加载器将由底层来实现,所以loader就为null了。