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()也拋出同樣的異常並中止。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章