JVM类加载器的分类(重点详解)

1 篇文章 0 订阅

JVM支持两种类型的类加载器:一种是引导类加载器,另外一种是自定义类加载器。

自定义类加载器:一般指的是程序中由开发人员自定义的一类类加载器,但是Java虚拟机规范中却没有这种定义,而是将所有派生于抽象类ClassLoader的类加载器都划分为自定义类加载器。

在Java中,无论如何我们将类加载器分为三种:引导类加载器(又叫启动类加载器)、扩展类加载器、系统类加载器(又叫应用程序类加载器)。

引导类加载器:这个类加载器是用C/C++语言实现的,嵌套在JVM的内部。它是用来加载Java的核心库(JAVA_HOME/jre/lib/rt/.jar、resources.jar或者sun.boot.class.path路径下的内容),用来加载JVM自身需要的类。它没有父类加载器,不继承于java.lang.ClassLoader,用来加载扩展类加载器和系统类加载器,指定其为它们的父类加载器。

注意:这里说的父类加载器说的不是父类与子类的继承关系,而是包含关系。

public class ClassLoaderTest {
    public static void main(String[] args) {
        //获取系统类加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2

        //获取其上层:扩展类加载器
        ClassLoader extClassLoader = systemClassLoader.getParent();
        System.out.println(extClassLoader);//sun.misc.Launcher$ExtClassLoader@4554617c

        //获取其上层:获取不到引导类加载器
        ClassLoader bootstrapClassLoader = extClassLoader.getParent();
        System.out.println(bootstrapClassLoader);//null

        //对于用户自定义类来讲:默认使用系统类加载器进行加载
        ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
        System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2

        //String类使用引导类加载器进行加载的。 --->java的核心类库都是使用引导类加载器进行加载的
        ClassLoader classLoader1 = String.class.getClassLoader();
        System.out.println(classLoader1);//null
    }
}

扩展类加载器:这个类加载器是由Java语言编写的,由sun.misc.Launcher$ExtClassLoader实现。派生于classLoader类,它的父类加载器为引导类加载器。从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK的安装目录的jre/lib/ext子目录(扩展目录)下加载类库。如果用户创建的JAR放在此目录下,也会自动由扩展类加载器加载。

系统类加载器:这个类也是由java语言编写,由sun.misc.Launcher$AppclassLoader实现。派生于classLoader类,它的父类加载器为扩展类加载器。它负责加载环境变量classpath或系统属性java.class.path指定路径下的类库。该类加载是程序中默认的类加载器,一般来说,Java应用的类都是由它来完成加载。通过ClassLoader.getSystemClassLoader ()方法可以获取到该类加载器 。

那么我们为什么要自定义类加载器呢?以及使用自定义类的好处?

因为我们需要的类不一定放在默认的类加载器加载的路径中,当我们需要特定路径下的class时,我们就需要自定义类加载器来加载我们所系要的类。使用自定义类加载器可以隔离加载类、修改类的加载方式、扩展加载源以及防止源码泄漏。

用户自定义类加载器实现的步骤:

1、开发人员可以通过继承抽象类java.lang.classLoader类的方式,实现自己的类加载器,以满足一些特殊的需求
2、在JDK2.0之前,在自定义类加载器时,总会去继承classLoader类并重写loadclass ()方法,从而实现自定义的类加载类,但是在JDK2.0之后已不再建议用户去覆盖loadclass ()方法,而是建议把自定义的类加载逻辑写在findclass ()方法中
3、在编写自定义类加载器时,如果没有太过于复杂的需求,可以直接继承URLClassLoader类,这样就可以避免自己去编写findclass ()方法及其获取字节码流的方式,这样会让自定义类加载器编写更为简单一些。

//自定义类加载器继承ClassLoader
public class CustomClassLoader extends ClassLoader {
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            //根据指定的路径以二进制流的方式读到内存里面形成一个字节数组
            byte[] result = getClassFromCustomPath(name);
            if (result == null) {
                //抛出文件未找到的异常对象
                throw new FileNotFoundException();
            } else {
                //findClass要和defineClass一起使用
                return defineClass(name, result, 0, result.length);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        //抛出类未找到的异常对象
        throw new ClassNotFoundException(name);
    }

    private byte[] getClassFromCustomPath(String name) {
        //从自定义路径中加载指定类
        //如果指定路径的字节码文件进行了加密,那么我们可以在此方法中进行解密操作,进行数据安全保障。
        return null;
    }

    public static void main(String[] args) {
        CustomClassLoader customClassLoader = new CustomClassLoader();
        try {
            Class<?> clazz = Class.forName("", true, customClassLoader);
            Object o = clazz.newInstance();
            System.out.println(o.getClass().getClassLoader());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值