深入java虛擬機器學習–類的載入機制(四)

luckyboys發表於2018-03-17

類載入的名稱空間

每個類載入器都有自己的名稱空間,名稱空間由所有以此載入器為初始類載入器的類組成,不同名稱空間的兩個類是不可見的,但只要得到類所對應的Class物件的refrence(反射),還是可以訪問另一個名稱空間的類資訊的。

同一個名稱空間內的類是相互可見的,子載入器的名稱空間包含所有父載入器的名稱空間,也就是說由子載入器載入的類能看到父載入器載入的類。例如:系統類載入器載入的類能看到根類載入器載入的類(使用者自定的類可以訪問java.lang.*包下的資訊),由父載入器載入的類不能看到子載入器載入的類。

如果兩個載入器之間沒有直接或者間接的父子關係,那麼它們個字載入的類相互不可見。

建立使用者自定義的類載入器

要建立使用者自定義的類載入器,只需要擴充套件java.lang.ClassLoader類,然後覆蓋它的findClass(String name)方法即可,該方法根據引數指定的類的名字,返回對應的Class物件的引用。

protected Class<?> findClass(String name) throws ClassNotFoundException {
        throw new ClassNotFoundException(name);
    }

我們可以按到ClassLoader裡面的findClass方法的預設實現會丟擲ClassNotFoundException異常,我們只需要在自定義的載入器裡面重寫,即可。

public class MyClassLoader extends ClassLoader
{

    private String name;//類載入器的名字
    private String path="";//載入類的預設路徑
    private String fileType=".class"; //class檔案的副檔名

    public MyClassLoader(String name){
        super();//讓系統類載入器成為該類載入器的父載入器
        this.name=name;
    }
    public MyClassLoader(ClassLoader parent,String name){
        super(parent);//顯示指定該類載入器的父載入器
        this.name=name;
    }

    @Override public String toString()
    {
        return this.name;
    }

    public String getPath()
    {
        return path;
    }

    public void setPath(String path)
    {
        this.path = path;
    }

    /**
     * 抽象類ClassLoader的findClass函式預設是丟擲異常的。而前面我們知道,
     * loadClass在父載入器無法載入類的時候,就會呼叫我們自定義的類載入器中的findeClass函式,
     * 因此我們必須要在loadClass這個函式裡面實現將一個指定類名稱轉換為Class物件.
     * @param name
     * @return
     */
    @Override protected Class<?> findClass(String name)
    {
        byte [] data=this.loadClassData(name);
        return this.defineClass(name,data,0,data.length);
    }

    private byte[] loadClassData(String name)
    {
        InputStream is=null;
        byte [] data=null;
        ByteArrayOutputStream baos=null;
        try
        {
            this.name=this.name.replace(".","\");
            is=new FileInputStream(new File(path+name+fileType));
            baos=new ByteArrayOutputStream();
            int ch=0;
            while(-1!=(ch=is.read())){
                baos.write(ch);
            }
            data= baos.toByteArray();
        }
        catch(Exception e){
         e.printStackTrace();
        }
        finally
        {
            try
            {
                is.close();
                baos.close();
            }
            catch(IOException e)
            {
                e.printStackTrace();
            }
        }
        return data;
    }

    public static void main(String[] args) throws Exception
    {
        MyClassLoader loader1 = new MyClassLoader("loader1");//沒有指定loader的父載入器,則預設的父載入器為系統類載入器
        loader1.setPath("G:\myapp\loader1\");

        MyClassLoader loader2 = new MyClassLoader(loader1,"loader2");//指定loader2的父載入器為loader1,這裡的loader1和loader2都為MyClassLoader的例項
        loader2.setPath("G:\myapp\loader2\");

        MyClassLoader loader3 = new MyClassLoader(null,"loader3");//bootstrap類載入器
        loader3.setPath("G:\myapp\loader3\");

        //test(loader1);
        test(loader2);
        test(loader3);
    }

    public static void test(ClassLoader loader) throws Exception
    {
        Class clazz=loader.loadClass("Sample");
        Object object=clazz.newInstance();
    }

 

開開心心編碼,快快樂樂生活。


相關文章