可以很清楚的看到,这种类的字面量定义其实不是加载类的方式,而是被编译器处理了,实质上是使用了Class.forName方法,但是使用这
种方式有一个很大的好处就是不用处理异常,因为编译器处理的时候如果找不到类会抛出一个NoClassDefFoundError.也许你觉得需要处理
ClassNotFoundException这种异常,事实上99%的情况下我们可以把这种异常认为是一个错误。
所以大部分情况我们使用这种方式会更简洁。
最常用的方式就是Class.forName方式了,这也是一个通用的上层调用。这个方法有两个重载,可能很多人都忽略了第二个方法。
public static Class forName(String name) throws
ClassNotFoundException
public static Class forName(String name, boolean
initialize,ClassLoader loader) throws ClassNotFoundException
第二个方法后面多了两个参数,第二个参数表示是否初始化,第三个参数为指定的类加载器。
在上面的例子中:
Class bb=Class.forName("B");
等价于
Class bb=Class.forName("B",true,Loader.class.getClassLoader());
这里要详细说一下这个类的初始化这个参数,如果这个参数为false的话,类中的static成员不会被初始化,static语句块也不会被执
行。
也就是类虽然被加载了,但是没有被初始化,不过在第一次使用时仍然会初始化。
所以我们有时候会看到Class.forName("XXX")。newInstance()这样的语句,为什么这里要创建一个不用的实例呢?
不过是为了保证类被初始化(兼容以前的系统)。
其实第二个方法是比较难用的,需要指定类加载器,如果不指定而且又没有安装安全管理器的化,是无法加载类的,只要看一下具体的实现就明白了。
最本质的方式当然是直接使用ClassLoader加载了,所有的类最终都是通过ClassLoader加载的,Class
cc=ClassLoader.getSystemClassLoader()。loadClass("C");这里通过使用系统类加载器来加载某个类,
很直接的方式,但是很遗憾的是通过这种方式加载类,类是没有被初始化的(也就是初始化被延迟到真正使用的时候)。不过我们也可以借鉴上面的经验,加载后实
例化一个对象Class
cc=ClassLoader.getSystemClassLoader()。loadClass("C")。newInstance()。
这里使用了系统类加载器,也是最常用的类加载器,从classpath中寻找要加载的类。
java中默认有三种类加载器:引导类加载器,扩展类加载器,系统类加载器。
java中的类加载有着规范的层次结构,如果我们要了解类加载的过程,需要明确知道哪个类被谁加载,某个类加载器加载了哪些类等等,就需要深入
理解ClassLoader的本质。