java 自定義類加載器


百度了一下,通篇全部都是啟動類加載器,擴展類加載器,應用程序類加載器,還有就是雙親委托模式 。

可是一圈下來,新手們依然不知道如何自定義一個類加載器,來生動的展現什么是類加載器。

首先我們在E:upload下新建一個a/BB.java文件。

代碼如下:

package a;

public class BB {
    private String a;
    public BB(){

    }
    public BB(String a){
        this.a=a;
    }
    public static void main(String[] args) {
         System.out.println("aaaaaaaaaa");
    }

}

  編譯后出現BB.class字節碼文件

退回到上級目錄,因為包是到a目錄的。執行java a.BB;正確執行main方法

  

現在我們回到IDea編輯器中,將BB.class文件讀取到內存,並且利用反射進行實例化。

自定義類加載器   MyClassLoader.java

package a;

import java.io.*;
import java.lang.reflect.Field;

public class MyClassLoader  extends ClassLoader{
    @Override
    protected Class<?> findClass(String name) {
        byte[] bytes=null;
        //將點替換成斜杠
        String fileName=name.replaceAll("\\.","/");
        StringBuilder sb=new StringBuilder("E:");
        sb.append(File.separator);
        sb.append("upload");
        sb.append(File.separator);
        sb.append(fileName);
        sb.append(".class");
        fileName=sb.toString();
        try {
            InputStream is=new FileInputStream(fileName);
            ByteArrayOutputStream bos=new ByteArrayOutputStream();
            byte[] buf=new byte[1024];
            int r=0;
            while ((r=is.read(buf))!=-1){
                bos.write(buf,0,r);
            }
            bytes=bos.toByteArray();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return defineClass(name,bytes,0,bytes.length);
    }

    public static void main(String[] args) throws Exception{
        //自定義類加載器對象1
        MyClassLoader c1=new MyClassLoader();
        String className="a.BB";
     //loadClass調用的就是findClass() Class clazz1
=c1.loadClass(className); //自定義類加載器對象2 MyClassLoader c2=new MyClassLoader(); Class clazz2=c2.loadClass(className); System.out.println(clazz1.getClassLoader()); System.out.println(clazz2.getClassLoader()); if(clazz1!=clazz2){ System.out.println("不同的類加載器對象加載相同的class文件,會產生不同的類對象"); } Object obj1=clazz1.getDeclaredConstructor(new Class[]{String.class}).newInstance("自定義加載器加載進內存的"); Field fa=clazz1.getDeclaredField("a"); fa.setAccessible(true);//將私有變量設置成可以訪問的權限 System.out.println(fa.get(obj1)); } }

執行結果:

e.MyClassLoader@2b193f2d
e.MyClassLoader@4dc63996
不同的類加載器加載相同的class文件,會產生不同的類對象
自定義加載器加載進內存的

很明顯clazz1和clazz2是兩個類。

給BB.java中構造器傳入的字符串:“自定義加載器加載進內存的”   也在上面打印出來了。

 

注意:如果將a/BB.java文件拷貝到idea編輯器中。那么MyClassLoader中的findClass就不會執行了。

因為MyClassLoader c1和MyClassLoader c2都繼承自ClassLoader,所以直接交給上級類加載器加載應用程序類加載器:Application ClassLoader;

應用程序類加載器會首先找到a/BB.class文件,並加入內存;此時就不會在繼續x向下傳播調用加載了。

類加載器在加載的時候虛擬機會首先調用加載器的私用方法loadClassInternal()

 

 而這個方法唯一作用就是調用自己的loadClass()方法,如果loadClass()加載失敗了,則會調用自己的findClass()。

loadClass()也能被重寫,但是我們不會這樣做,因為這樣做的話,所有的類都會走這個方法來加載類;那么虛擬機內置的一些類也會用這個方法里面的邏輯來加載,固定會報錯。

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM