双亲委托模型

工作过程可以分为两步:
- 首先从底向上的检查类是否已经加载过,就是这行代码:Class<?> c = findLoadedClass(name);
- 如果都没有加载过的话,那么就自顶向下的尝试加载该类。
demo
public class MyClassLoader extends ClassLoader {
    //指定路径
    private String path ;
    public MyClassLoader(String classPath){
        path=classPath;
    }
    /**
     * 重写findClass方法
     * @param name 是我们这个类的全路径
     * @return
     * @throws ClassNotFoundException
     */
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class log = null;
        // 获取该class文件字节码数组
        byte[] classData = getData();
        if (classData != null) {
            // 将class的字节码数组转换成Class类的实例
            log = defineClass(name, classData, 0, classData.length);
        }
        return log;
    }
    /**
     * 将class文件转化为字节码数组
     * @return
     */
    private byte[] getData() {
        File file = new File(path);
        if (file.exists()){
            FileInputStream in = null;
            ByteArrayOutputStream out = null;
            try {
                in = new FileInputStream(file);
                out = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int size = 0;
                while ((size = in.read(buffer)) != -1) {
                    out.write(buffer, 0, size);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return out.toByteArray();
        }else{
            return null;
        }
    }
}源码分析

this.getClass().getClassLoader().loadClass("com.xxx.Test.class") ;

findLoadedClass 此方法负责从当前ClassLoader实例对象的缓存中寻找已加载的类,调用的为native方法。
findClass 此方法直接抛出ClassNotFoundException异常,因此要通过覆盖loadClass或此方法来以自定义的方式加载相应的类。

findSystemClass 此方法是从sun.misc.Launcher$AppClassLoader中寻找类,如果未找到,则继续从BootstrapClassLoader中寻找,如果仍然未找到,返回null

defineClass 此方法负责将二进制字节流转换为Class对象,这个方法对于自定义类加载器而言非常重要。如果二进制的字节码的格式不符合jvm class文件格式规范,则抛出ClassFormatError异常;如果生成的类名和二进制字节码不同,则抛出NoClassDefFoundError;如果加载的class是受保护的、采用不同签名的,或者类名是以java.开头的,则抛出SecurityException异常。


resolveClass 此方法负责完成Class对象的链接,如果链接过,则直接返回。

双亲委派模型的好处:
(1)主要是为了安全性,避免用户自己编写的类动态替换 Java的一些核心类,比如 String。
(2)同时也避免了类的重复加载,因为 JVM中区分不同类,不仅仅是根据类名,相同的 class文件被不同的 ClassLoader加载就是不同的两个类。
常见异常
ClassNotFoundException: 这是最常见的异常,产生这个异常的原因为在当前的ClassLoader 中加载类时,未找到类文件,
NoClassDefFoundError:这个异常是因为加载到的类中引用到的另外类不存在,例如要加载A,而A中盗用了B,B不存在或当前的ClassLoader无法加载B,就会抛出这个异常(比如jar包冲突,引入了低版本的jar)。
LinkageError:该异常在自定义ClassLoader的情况下更容易出现,主要原因是此类已经在ClassLoader加载过了,重复的加载会造成该异常(比如jar冲突导致)。
能不能自己写个类叫java.lang.System? 不能。
为了不让我们写System类,类加载采用委托机制,这样可以保证爸爸们优先,爸爸们能找到的类,儿子就没有机会加载。而System类是Bootstrap加载器加载的,就算自己重写,也总是使用Java系统提供的System,自己写的System类根本没有机会得到加载。
如何打破 ClassLoader 双亲委托?
重写 loadClass() 方法。









