天天看點

深入java虛拟機學習 -- 類的加載機制(四)

類加載的命名空間

每個類加載器都有自己的命名空間,命名空間由所有以此加載器為初始類加載器的類組成,不同命名空間的兩個類是不可見的,但隻要得到類所對應的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();
    }      

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