Class.forName(String className) 实例化对象问题

来源:互联网 发布:js跳转微信打开链接 编辑:程序博客网 时间:2024/06/03 17:06

在实验课上用xml配置文件实现工厂模式,其中用配置文件返回类实例时出现了一点小问题,故记之。

问题的描述:工厂方法模式日志记录器。某系统日志记录器要求支持多种日志记录方式,如文件日志记录(FileLog)、数据库日志记录(DatabaseLog)等,且用户可以根据要求动态选择日志记录方式,现使用工厂模式设计该系统。

    该工厂的类图如下:

实现代码:

package com.log;//产品interface Log {public void writeLog();}class DataBaseLog implements Log {public void writeLog() {System.out.println("写入数据库");}}class FileLog implements Log {public void writeLog() {System.out.println("写入文件");}}//工厂interface LogFactory {public Log createLog();}class FileLogFactory implements LogFactory {public Log createLog(){return new FileLog();}}class DataBaseLogFactory implements LogFactory {public Log createLog(){return new DataBaseLog();}}public class Client{public static void main(String[] args) {//创建工厂LogFactory lgfactory = new DataBaseLogFactory();//创建日志产品Log lg = lgfactory.createLog();//调用写日志方法lg.writeLog();}}


现需要从xml配置文件中读取具体工厂名,并返回工厂对象,这里使用java中的反射机制中的Class接口,其Class.forName(String className)方法可以返回与带有给定字符串名的类或接口相关联的Class对象,再通过Class对象的newInstance()方法创建此对象表示的类的一个新实例,即通过一个类名字符串得到类的实例。

如创建一个字符串类型的对象,其代码如下:

Class c = Class.forName("String");Object obj = c.newInstance();return obj;

值得注意的是这里的String类是包java.lang的类,每个java文件都会默认引入这个包。


再看配置文件:

<?xml version="1.0" encoding="UTF-8"?><config><className>DataBaseLogFactory</className></config>
很简单,就是放置一个具体工厂类名。

通过获取配置文件中预先设置的类名,再利用反射机制获取类对象。通过引入DOM和反射机制后,可以在XMLUtil中实现读取XML文件并根据存储在XML文件中的类名获取对应的对象,XMLUtil类的详细代码如下:

package com.log;import javax.xml.parsers.*;import org.w3c.dom.*;import org.xml.sax.*;import java.io.*;public class XMLUtil {@SuppressWarnings("unchecked")public static Object getBean(){try{//创建DOM文档对象DocumentBuilderFactory dFactory= DocumentBuilderFactory.newInstance();DocumentBuilder builder = dFactory.newDocumentBuilder();Document doc = builder.parse(new File("D:\\Junior\\DesignPartern\\Log\\src\\com\\log\\config.xml"));//注意这里使用配置文件的绝对路径 //获取包含结点类名的文本结点NodeList nl = doc.getElementsByTagName("className");Node classNode = nl.item(0).getFirstChild();String cName = classNode.getNodeValue();//System.out.println(cName);//通过类名生成实例对象并将其返回Class c = Class.forName(cName);Object obj = c.newInstance();return obj;} catch(Exception e){e.printStackTrace();return null;}}}
将主测试类代码改为:

public class Client{public static void main(String[] args) {try {//创建工厂LogFactory lgfactory = (LogFactory)XMLUtil.getBean();//创建日志产品Log lg = lgfactory.createLog();//调用写日志方法lg.writeLog();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}

在实验时,结果出现了错误:

java.io.FileNotFoundException: D:\Junior\DesignPartern\Log\config.xml (系统找不到指定的文件。)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(Unknown Source)
at java.io.FileInputStream.<init>(Unknown Source)
at java.io.FileInputStream.<init>(Unknown Source)
at sun.net.www.protocol.file.FileURLConnection.connect(Unknown Source)

后来经逐步测试发现错误出现在XMLUtil.java文件中的 

Class c = Class.forName(cName);

这里从配置文件获取的类名只是一个类名字符串,

Class.forName()主要功能
Class.forName(xxx.xx.xx)返回的是一个类
Class.forName(xxx.xx.xx)的作用是要求JVM查找并加载指定的类,
也就是说JVM会执行该类的静态代码段。

我们再来看api文档中提供的关于Class.forName的详细解释:

  • forName

    public static Class<?> forName(String className)                        throws ClassNotFoundException
    Returns the Class object associated with the class or interface with the given string name. Invoking this method is equivalent to:
    Class.forName(className, true, currentLoader)
    where currentLoader denotes the defining class loader of the current class.

    For example, the following code fragment returns the runtime Class descriptor for the class namedjava.lang.Thread:

    Class t = Class.forName("java.lang.Thread")

    A call to forName("X") causes the class named X to be initialized.

    Parameters:
    className - the fully qualified name of the desired class.
    Returns:
    the Class object for the class with the specified name.
    Throws:
    LinkageError - if the linkage fails
    ExceptionInInitializerError - if the initialization provoked by this method fails
    ClassNotFoundException - if the class cannot be located 
注意黑色加粗的部分,这里的className要使用类的路径,如上述的java.lang.Thread,即包名.类名

修改后的XMLUtil.java文件,

try{...Class c = Class.forName("com.log."+cName);//使用类的全路径Object obj = c.newInstance();return obj;}catch(Exception e){e.printStackTrace();return null;}


问题解决,运行结果如下:


通过解决这个问题,得出以下结论:要仔细阅读API文档提供的帮助和样例微笑

阅读全文
0 0