在java项目开发中,Class.forName应用得很多。例如应用在加载jdbc驱动时,Class.forName("com.mysql.jdbc.Driver")。本篇主要介绍一下Class.forName静态方法的应用范围和使用方法。
话不多说,以笔者的代码抛砖引玉整体代码太过冗长,特截取一段:
// 获取内部窗体的唯一实例对象
private JInternalFrame getIFrame(String frameName) {//传入的字符参数为类的名称
JInternalFrame jf = null;
if (!ifs.containsKey(frameName)) {//如果映射中未存在
try { //寻找到并执行那个子窗体类
Class fClass = Class.forName("internalFrame." + frameName);//根据项目文件的路径加载对应的类
Constructor constructor = fClass.getConstructor(null);//获取类构造器
jf = (JInternalFrame) constructor.newInstance(null);//类加载机制
ifs.put(frameName, jf);//加入映射
} catch (Exception e) {
e.printStackTrace();
}
} else
jf = ifs.get(frameName);//已存在则直接调用
return jf;
}
笔者写的java程序是一个模拟桌面的小的java系统,在JDesktopPane的基础上调用JInternalFrame内部窗体实现桌面模式的模拟。在过程中用到以上代码中的函数实现根据内部窗体名加载对应的内部窗体。
从上文代码不难看出,Class.forName实现的功能。本文中向forName()方法传入类在项目下所在的地址即可实现对应地址下类的加载。而在理解方法前不妨先了解一下java的反射机制。Java反射是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等)、superclass(例如Object)、实现之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。Java反射机制容许程序在运行时加载、探知、使用编译期间完全未知的classes。换言之,Java可以加载一个运行时才得知名称的class,获得其完整结构。
在java中任何类的运行的前提都是在jvm上装载,这个方法的功能就是类的动态加载,但需要和new关键字进行区分。从jvm的角度看,我们使用关键字new创建一个类的时候,这个类可以没有被加载。但是使用newInstance()方法的时候,就必须保证:1、这个类已经加载;2、这个类已经连接了。而完成上面两个步骤的正是Class的静态方法forName()所完成的,这个静态方法调用了启动类加载器,即加载 java API的那个加载器。 现在可以看出,newInstance()实际上是把new这个方式分解为两步,即首先调用Class加载方法加载某个类,然后实例化。 这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好的灵活性。
最终总结new关键字和newInstance()方法的区别: newInstance: 弱类型。低效率。只能调用无参构造。 new: 强类型。相对高效。能调用任何public构造。
而和Class.forName(String className)相类似的还有方法:classLoader.loadClass(StringclassName , boolean resolve),不同的是前者默认使用装载当前类实例的类装载器来装载指定类,后者需要手动指定一个类装载器的实例。而在是否实例化类方面,前者默认实例化后者调用时并不实例化。以上为两个类加载方法的不同。
本文简介了Class.forName的使用方法和实现机制,并简述了和new关键字及classLoader.loadClass()函数的区别。
看来项目开发中的学问太多太多,精益求精弄懂每一行代码才能一点一滴地进步。