1. 程式人生 > >自定義類加載器

自定義類加載器

code pac 路徑 中轉 efi sync protected tool 解析

自定義類加載器一般步驟大概為

1. 繼承 ClassLoader 類

2. 復寫 findClass方法

在findClass方法中傳入一個String類型參數

一般為類所在的路徑可以為網絡url,或者本地路徑。加上類的名稱。

先檢查類所在的包是否存在getPackage方法

如果不存在通過父類的definePackage方法定義包

通過路徑找到類所在位置,再將對應的類l加載到內存中轉換為byte數組

再通過父類的 defineClass生成一個類的對象返回

protected Class findClass(String name) throws ClassNotFoundException {
        
byte[] classfile; try { if (this.source != null) { if (this.translator != null) { this.translator.onLoad(this.source, name); } try { classfile = this.source.get(name).toBytecode(); }
catch (NotFoundException var7) { return null; } } else { String jarname = "/" + name.replace(‘.‘, ‘/‘) + ".class"; InputStream in = this.getClass().getResourceAsStream(jarname); if (in == null) {
return null; } classfile = ClassPoolTail.readStream(in); } } catch (Exception var8) { throw new ClassNotFoundException("caught an exception while obtaining a class file for " + name, var8); } int i = name.lastIndexOf(46); if (i != -1) { String pname = name.substring(0, i); if (this.getPackage(pname) == null) { try { this.definePackage(pname, (String)null, (String)null, (String)null, (String)null, (String)null, (String)null, (URL)null); } catch (IllegalArgumentException var6) { ; } } } return this.domain == null ? this.defineClass(name, classfile, 0, classfile.length) : this.defineClass(name, classfile, 0, classfile.length, this.domain); }

3. 還可復寫loadClass方法

一般先通過 findLoadedClass確定類是否已經被加載過,加載過則可以不用重新加載

還可以將一些類交給父加載器加載,比如jdk自己的類

還可調用父類的resolveClass方法,對類進行解析,這個沒大看懂

protected Class loadClass(String name, boolean resolve) throws ClassFormatError, ClassNotFoundException {
        name = name.intern();
        synchronized(name) {
            Class c = this.findLoadedClass(name);
            if (c == null) {
                c = this.loadClassByDelegation(name);
            }

            if (c == null) {
                c = this.findClass(name);
            }

            if (c == null) {
                c = this.delegateToParent(name);
            }

            if (resolve) {
                this.resolveClass(c);
            }

            return c;
        }
    }

4. 類加載器定義好了之後就可以通過自定義的類加載器對類進行加載了

public void testClassLoader5(){
        Loader myClassLoader = new Loader();
        for(int i=0;i<10;i++){
            try {
                Class clz = Class.forName("tools.Dump ",true,myClassLoader);
                Field[] declaredFields = clz.getDeclaredFields();
                LOGGER.info(clz.newInstance().getClass().getClassLoader().toString());
            }catch (Exception e){
                LOGGER.error("class loader error",e);
            }
        }
    }

5. 例子中加載了tools.Dump 這個類,並通可以通過反射的方式生成一個這個類的對象,

但是卻不能直接將這個對象直接賦值給tools.Dump 類型的變量,因為這個類已經被系統加載器加載過了。賦值的時候會報類型轉換異常的錯誤,以為雖然包名、類名都相同但是類加載器不同。

自定義類加載器