类加载器(2)-自定义类加载器

ClassLoader

有2个重要方法:

Class<?> loadClass(String name, boolean resolve)

Class<?> findClass(String name)

//双亲委派查找类
protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
}

// 在双亲中查不到,就可以到这个自定义实现查找类的方法去加载类
protected Class<?> findClass(String name) throws ClassNotFoundException {
        throw new ClassNotFoundException(name);
}

自定义ClassLoader

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class MyClassLoader extends ClassLoader {
    private String libPath;

    public MyClassLoader(String path) {
        libPath = path;
    }

    /**
     * 重写查找类方法
     *
     * 默认走双亲委派,最后找不到通过findClass到指定目录中去加载class
     *
     * @param name
     * @return
     * @throws ClassNotFoundException
     */
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        String fileName = getFileName(name);
        File file = new File(libPath, fileName);
        try {
            FileInputStream is = new FileInputStream(file);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            int len = 0;
            try {
                while ((len = is.read()) != -1) {
                    bos.write(len);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            byte[] data = bos.toByteArray();
            is.close();
            bos.close();
            return defineClass(name, data, 0, data.length);

        } catch (IOException e) {
            e.printStackTrace();
        }
        return super.findClass(name);
    }

    /**
     * 获取要加载 的class文件名
     * @param name
     * @return
     */
    private String getFileName(String name) {
        int index = name.lastIndexOf('.');
        if (index == -1) {
            return name + ".class";
        } else {
            return name.substring(index + 1) + ".class";
        }
    }

}

编写测试类

public interface ISpeak {
    void speak();

    void write(String value);
}
public class Speak implements ISpeak {

    public static String name = "one";

    @Override
    public void speak() {
        System.out.println("speak" + name);
    }

    @Override
    public void write(String value) {
        name=value;
    }

}

将speak类生成字节码后,放到 F:\lib\appone 和 F:\lib\apptwo 目录中,然后将speak.java 删除,重新编译项目,后面通过classload 加载指定目录的 class 字节码文件

测试例子

/**
 * 将编译好的speak.class 放到  F:\lib\appone 和 F:\lib\apptwo 目录中
 *
 * 演示不同类加载器加载,不同目录中,同1个命名空间类,类被加载后已经不是同1个类了
 */
public class ClassloaderApp {

    public static void main(String[] args) {
        ISpeak speak1=null;
        ISpeak speak2=null;
        ISpeak speak3=null;
        ISpeak speak4=null;

        final MyClassLoader myClassLoader1 = new MyClassLoader("F:\\lib\\appone");
        try {
            Class cls1  = myClassLoader1.loadClass("cn.sing.classload.defineclassload.speak.Speak");
            System.out.println(cls1.getClassLoader().toString());
            if(cls1 != null){
                try {
                    speak1 = (ISpeak)cls1.newInstance();
                    speak1.speak();
                    speak3 = (ISpeak)cls1.newInstance();
                    speak3.speak();
                    //Method method = cls1.getDeclaredMethod("speak",null);
                    //method.invoke(obj, null);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }


        final MyClassLoader myClassLoader = new MyClassLoader("F:\\lib\\apptwo");
        try {
            Class c = myClassLoader.loadClass("cn.sing.classload.defineclassload.speak.Speak");
            System.out.println(c.getClassLoader().toString());
            if(c != null){
                try {
                    speak2 = (ISpeak)c.newInstance();
                    speak2.speak();
                    speak4 = (ISpeak)c.newInstance();
                    speak4.speak();
                    //Method method = c.getDeclaredMethod("speak",null);
                    //method.invoke(obj, null);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }


        //默认AppClassLoader加载
        System.out.println(ISpeak.class.getClassLoader().toString());

        // speak1 myClassLoader1
        System.out.println(speak1.getClass().getClassLoader().toString());
        // speak1 父加载器是  AppClassLoader ,但是 speak1 不是通过 AppClassLoader 加载的
        System.out.println(speak1.getClass().getClassLoader().getParent().toString());

        // speak2 myClassLoader2
        System.out.println(speak2.getClass().getClassLoader().toString());
        // speak2 父加载器是  AppClassLoader ,但是 speak2 不是通过 AppClassLoader 加载的
        System.out.println(speak2.getClass().getClassLoader().getParent().toString());

        //改变静态变量值
        speak1.write("app-one");
        speak2.write("app-two");

        //speak1 和 speak3 属于同1个加载器
        speak1.speak();
        speak3.speak();

        //speak2 和 speak4 属于同1个加载器
        speak2.speak();
        speak4.speak();

    }
}

运行结果

cn.sing.classload.defineclassload.MyClassLoader@3764951d
speakone
speakone
cn.sing.classload.defineclassload.MyClassLoader@4d7e1886
speakone
speakone
sun.misc.Launcher$AppClassLoader@18b4aac2
cn.sing.classload.defineclassload.MyClassLoader@3764951d
sun.misc.Launcher$AppClassLoader@18b4aac2
cn.sing.classload.defineclassload.MyClassLoader@4d7e1886
sun.misc.Launcher$AppClassLoader@18b4aac2
speakapp-one
speakapp-one
speakapp-two
speakapp-two

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值