类加载

  类怎么加载的?当然就是通过ClassLoader加载的了。那具体是怎么加载的?这个就不是很清楚了。查了下资料才发现,具体加载模型有个名词,叫双亲委派。意思就是一个类加载器如果收到了加载请求,先找爸妈去加载,而不会自己做这件事。如果它爸妈收到儿女的委派,而且爸妈的爸妈还健在,那么爸妈也不能自己做主,接着请示爸妈的爸妈去加载。每一层加载器都必须先委派给父加载器,只有父加载器找不到要加载的类,才会由下一层加载器处理。我们来看图:

  不同加载器搜索的范围不同,启动类加载器只搜JAVA_HOMElib目录,扩展类加载器只搜JAVA_HOMElibext目录,应用程序类加载器只搜classpath目录。双亲委派的目的就是实现加载的优先级,避免同名类加载的混乱,避免通过自定义类加载器来恶意加载类达到替换标准API的目的。如果同一个class文件由不同的类加载器来加载,那么对应会有两个不同的实例。下面看下代码:

package com.wulinfeng.io;

import static java.lang.System.out;

import java.io.InputStream;

import sun.text.resources.cldr.FormatData;

public class ClassLoad {

    public static void main(String[] args) throws Exception {
        // 加载一个在jre/lib/ext目录下的类FormatData.class
        Class clzEXT = FormatData.class;
        ClassLoader loader = clzEXT.getClassLoader();
        out.println("FormatData.class的类加载器:" + loader.getClass());
        out.println("FormatData.class的类加载器的父母:" + loader.getParent());

        // 加载一个在classpath下的类ClassLoad.class
        Class clzApp = ClassLoad.class;
        ClassLoader loader2 = clzApp.getClassLoader();
        out.println("ClassLoad.class的类加载器:" + loader2.getClass());
        out.println("ClassLoad.class的类加载器的父母:" + loader2.getParent());
        out.println("ClassLoad.class的类加载器的祖父母:" + loader2.getParent().getParent());

        // 自定义类加载器
        ClassLoader newLoader = new ClassLoader() {
            @Override
            public java.lang.Class<?> loadClass(String name) {
                try {
                    String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class";
                    InputStream is = getClass().getResourceAsStream(fileName);
                    if (is == null) {
                        return super.loadClass(name);
                    }
                    byte[] b = new byte[is.available()];
                    is.read(b);
                    return defineClass(name, b, 0, b.length);
                } catch (Exception e) {
                    System.err.println(e);
                }
                return null;
            }
        };

        out.println("自定义的类加载器:" + newLoader.getClass());
        out.println("自定义的类加载器的父母:" + newLoader.getParent());
        out.println("自定义的类加载器的祖父母:" + newLoader.getParent().getParent());
        // 使用自定义加载器加载ClassLoad.class,与application加载器得到的实例是不同的
        Object o = newLoader.loadClass("com.wulinfeng.io.ClassLoad").newInstance();
        out.println(o instanceof com.wulinfeng.io.ClassLoad);
    }
}

  输出结果:

FormatData.class的类加载器:class sun.misc.Launcher$ExtClassLoader
FormatData.class的类加载器的父母:null
ClassLoad.class的类加载器:class sun.misc.Launcher$AppClassLoader
ClassLoad.class的类加载器的父母:sun.misc.Launcher$ExtClassLoader@33909752
ClassLoad.class的类加载器的祖父母:null
自定义的类加载器:class com.wulinfeng.io.ClassLoad$1
自定义的类加载器的父母:sun.misc.Launcher$AppClassLoader@73d16e93
自定义的类加载器的祖父母:sun.misc.Launcher$ExtClassLoader@33909752
false
原文地址:https://www.cnblogs.com/wuxun1997/p/6524696.html