java 动态扩展方式

java 除了在运行时连接类型之外,还可以在运行时动态决定连接哪一种类型。java的体系结构允许动态扩展java程序,过程包括运行时决定所使用的类型,装载它们,使用它们。

一、动态扩展的方法

通过传递类型的名称,使用java.lang.class的forName()方法。

通过用户自定义的类装载器的loadClass()方法,用户自定义的类装载器可以从java.class.ClassLoader的任何子类创建。

二、动态扩展的例子:

浏览器启动的时候,不知道将要从网络上装载的class的文件,当遇到applet的网页时才知道每个applet所需的类和接口的名字。

三、程序:

1、使用java.lang.class的forName()方法:

public class TestClass {
    public void hello() {
        System.out.println("Hello,World!");
    }
}


public class TestForName {

    /**
     *
     * @param args
     */
    public static void main(String args[]) {
        if (args.length == 0) {
            System.out.println("please input the class name!");
            return;
        }
        for (int i = 0; i < args.length; i++) {
            try {
                Class c = Class.forName(args[i]);
                Object obj = c.newInstance();
                TestClass tc = (TestClass) obj;
                tc.hello();
            } catch (ClassNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }
}

程序解析:

forName()接受的字符串参数是类型的全限定名称,如果成功装载了类型,或者之前已经被成功装载过,会返回代表类型的Class的实例,如果不成功,将会抛出ClassNotFoundException异常。

forName()试图确认所需的类型被装载到当前命名空间中,这个当前的命名空间就是类型所属的定义类装载器的命名空间。如果没有明确地在命令行或者环境变量中指定一个类的路径,系统类装载器会在当前目录中寻找所需的类型。

2、使用自定义的类装载器的loadClass()方法 方法:

程序:

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * @author hansen
 *
 */
public class TestClassLoader extends ClassLoader {

    private String basePath;

    /**
     * constructor
     *
     * @param basePath
     */
    public TestClassLoader(String basePath) {
        this.basePath = basePath;
    }

    /**
     * constructor
     *
     * @param parent
     * @param basePath
     */
    public TestClassLoader(ClassLoader parent, String basePath) {
        super(parent);
        this.basePath = basePath;
    }

    /*
     * (non-Javadoc)
     *
     * @see java.lang.ClassLoader#findClass(java.lang.String)
     */
    @Override
    protected Class findClass(String className)
            throws ClassNotFoundException {
        byte[] classData = getTypeFromBasePath(className);
        if (null == classData) {
            throw new ClassNotFoundException();
        }
        return defineClass(className, classData, 0, classData.length);
    }

    /**
     * get the class type from the base path
     *
     * @param typeName
     * @return
     */
    private byte[] getTypeFromBasePath(String typeName) {
        FileInputStream in = null;
        String fileName = basePath + File.separatorChar
                + typeName.replace('.', File.separatorChar) + ".class";
        try {
            in = new FileInputStream(fileName);
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        BufferedInputStream input = new BufferedInputStream(in);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            int c = input.read();
            while (c != -1) {
                out.write(c);
                c = input.read();
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return out.toByteArray();
    }
}

解析:

findClass的工作方式:

1、接受需要装载的类型的全限定名称作为唯一的参数。首先试图查找或者生生成一个字节数组,内容是java class文件格式,文件格式定义了所需要装载的类型。

2、如果findClass()无法确定或者生成字节数组,会抛出ClassNotFoundException()异常并中止。否则findClass()调用defineClass(),把所需的类型名称、字节数组和一个可选的指定了这个类型所属的受保护域的ProtectionDomain对象作为参数。

3、如果defineClass()返回了一个代表这个类型的Class实例,findClass()简单地吧同一个Class实例返回给它的调用者。否则,defineClass()抛出某些异常并中止findClass()也抛出同样的异常并中止。

你可能感兴趣的:(Java)