菜鳥學JAVA之——類加載

類加載

類加載器(ClassLoader)

什麼是類加載器?

就是Java代碼在運作,JVM在啓動時,把類模板加載到內存去的工具

首先,一個Java程序真正的執行過程應該是你去調用了Java這個命令,然後程序開始執行,而執行的過程中,JVM會將很多類(.class文件,或者.jar文件)加載到當前的程序內存當中。

當你去寫 類型 a = new 類型()時,類加載器就會把加載好的模板放到堆中申請空間並佔用空間,把東西加載到內存中。

類加載器的分類
在這裏插入圖片描述
真正獲得類模板的過程,是通過一個叫做ClassLoader的工具來獲得到的

作用:ClassLoader就是將一個存在於系統文件中的.class文件,加載到當前程序的內存當中,變成JVM中的一個對象、一個類模板,Java語言就可以識別這個Class類型

把類模板加載到工程中

問題:現有一個類的對象和他的.class文件,需要加載出這個類,生成一個對象。

defineClass():把這二進制文件變成我們想要的Class文件

首先自定義一個類加載器,返回的就是由Cent.class文件生成的類模板

public class MyClassLoader extends ClassLoader {

    /*
        //把從外部看到的.class文件變成內存中,在代碼中看到的Class文件(類模板),並且用這個Class來創建對象,這個.class文件在哪不用關心
        defineClass()//第二個參數數組存放的就是.class文件轉換成的二進制碼的數組,可以把這二進制文件變成我們想要的Class文件

     */

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        //找到那個.class文件,用文件流懟到這個文件上
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("Z:/Cent.class");
            byte[] b = new byte[fis.available()];
            fis.read(b);
            return defineClass(name,b,0,b.length);//defindClass就是定義class的,是ClassLoader給出的
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return super.findClass(name);
    }
}

ObjectInputStream使用了自己的類加載器(應用加載器),並不能加載出我們想要加載的那個類現在需要ObjectInputStream在加載我們的類時使用我們自定義的類加載器,加載其他類時使用自己的類加載器這時就需要繼承ObjectInputStream,重寫他的resolveClass方法了

重寫ObjectInputStream的類加載器

public class MyObjectInputStream extends ObjectInputStream {

    private ClassLoader classLoader;

    public MyObjectInputStream(InputStream in) throws IOException {
        super(in);
    }

    public MyObjectInputStream(InputStream in, ClassLoader classLoader) throws IOException {
        super(in);
        this.classLoader = classLoader;
    }

    @Override
    protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
        //如果可以創建對象成功就用的自己的類加載器,如果不成功,就捕獲異常,用父類的類加載器創建對象
        try {
            return Class.forName("baidu.ali.tencent.Cent",false,this.classLoader);//第二個參數initialize:說明這個類是否必須初始化。
            /*
            //當然這裏除了上面那樣寫,也可以像下面這樣寫,這是下面這樣的寫法具有侷限性,讓MyObjectInputStream類加載器只能加載這一種外部的類,不能加載其他類型的外部類
            MyClassLoader loader = new MyClassLoader();
            Class aClass = loader.loadClass("baidu.ali.tencent.Cent");
            return aClass;
            */
        } catch (Exception e) {
            return super.resolveClass(desc);
        }
    }
    
}
ublic class HomeworkDemo {
    public static void main(String[] args) {
        MyClassLoader loader = new MyClassLoader();
        try {
            Class clazz = loader.loadClass("baidu.ali.tencent.Cent");//用自己定義的類加載器拿到了類模板了,加載的只是一個類型,還並不是對象
            
            /*
            ObjectInputStream使用了自己的類加載器(應用加載器),他只能加載寫在工程裏的類,並不能加載出我們想要加載的那個類
            現在需要ObjectInputStream在加載我們的類時使用我們自定義的類加載器,加載其他類時使用自己的類加載器
            這時就需要繼承ObjectInputStream,重寫他的resolveClass方法了
             */
            ObjectInputStream ois = new MyObjectInputStream(new FileInputStream("Z:/object.lgc"),loader);//用loader把類型加載出來
            Object object = ois.readObject();//成功的將外部我們想要加載的類加載進來了,生成了object對象


        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章