java基础——类加载器

类加载器

首先我们要知道 .class 文件存储是类的基本信息。

类加载

每个 .java 文件经过编译就会产生一个 .class 文件,当我们需要某个类,虚拟机就会将它的 .class 文件加载到虚拟机的内存,并创建相应的 class 对象,这就是类加载的过程。

类加载器的目标

类加载器就是实现这个类加载的过程。

那么类加载器是如何区分类的呢?主要是因为 SUN 公司规定了每个 class 文件的开头必须以 0xCAFEBABE(也称为魔数) 开头,这使得类加载器可以区分出来。

类加载器

虚拟机里提供了三种类加载器,分别是启动(Bootstrap)类加载器、扩展(Extension)类加载器、系统(System)类加载器(也称应用类加载器)。

类加载器
加载器 功能
Bootstrap ClassLoader 启动类加载器 也称引导类加载器或者根加载器,主要加载 jar/lib/rt.jar 文件。
Ext ClassLoader 扩展类加载器 主要加载核心扩展类,即 JAVA_HOME/jre/lib/ext 下的jar 文件。
App ClassLoader 系统类加载器 主要加载用户自定义的类,classPath 下的 jar 文件和目录。 

类加载的方式——双亲委派方式

其加载原理是如果子类收到了一个类加载的请求,子类不会去处理这个请求,而是把请求交给父类,如果父类还有父类,就继续传递请求给父类,直到到达根加载器。如果根加载器完成加载任务就成功返回,否叫交给子类去处理。这是一个递归的过程。



    protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            
            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) {
                   
                }
                 //父类没加载成功
                if (c == null) {
                    
                    long t1 = System.nanoTime();
                    c = findClass(name);

                   
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    

这个代码实现了类加载的双亲委派机制。

其中有几个比较重要的方法 findClass 方法和 defineClass 方法。

findClass:根据类的包路径找到 class 文件。

defineClass :负责从 class 字节码中加载 Class 对象,然后 Class 对象通过反射机制生成对象。

当我们去写自己的自定义类加载器时,不用每次都重写 loadClass 方法,这样会破坏它的双亲委派机制,只需要重写 findClass方法就好了。


猜你喜欢

转载自blog.csdn.net/alyson_jm/article/details/80460665