• Java --- JVM类加载器


    目录

    一、类加载器

     1.1、启动类加载器(引导类加载器,Bootstrap classLoader)

    1.2、扩展类加载器(Extension classLoader)

    1.3、应用程序类加载器(系统类加载器,AppclassLoader)

    1.4、用户自定义类加载器

    二、ClassLoader

    2.1、获取ClassLoader的方法


    一、类加载器

    1、JVM支持两种类型的类加载器,分别为引导类加载器(BootstrapClassLoader)和自定义类加载器(User-Defined ClassLoader)。

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

    3、无论类加载器的类型如何划分,在程序中我们最常见的类加载器始终只有3个。

     四者之间的关系是包含关系。不是上层下层,也不是子父类的继承关系

     测试代码:

    1. public class ClassLoaderTest {
    2. public static void main(String[] args) {
    3. //获取系统类加载器
    4. ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
    5. System.out.println("类加载器:" + systemClassLoader);
    6. //获取systemClassLoader的上层扩展类加载器
    7. ClassLoader extClassLoader = systemClassLoader.getParent();
    8. System.out.println("systemClassLoader上层扩展类加载器:" + extClassLoader);
    9. //获取extClassLoader的上层扩展类加载器
    10. ClassLoader bootstrapClassLoader = extClassLoader.getParent();
    11. System.out.println("extClassLoader上层扩展类加载器:" +bootstrapClassLoader);//获取不到引导类加载器
    12. //获取用户自定义类的类加载器
    13. ClassLoader classLoader = ClassInitTest.class.getClassLoader();
    14. System.out.println("用户自定义类的类加载器:" + classLoader);//默认使用系统类加载器
    15. //查看String类的类加载器
    16. //String类使用引导类加载器,即Java的核心都是使用引导类加载器
    17. ClassLoader classLoader1 = String.class.getClassLoader();
    18. System.out.println("String类的类加载器:" + classLoader1);
    19. }
    20. }

     1.1、启动类加载器(引导类加载器,Bootstrap classLoader)

    ①、这个类加载使用c/C++语言实现的,嵌套在JVM内部。

    ②、它用来加载Java的核心库(JAVA_HOME/jre/ lib/rt.jar、resources.jar或sun.boot.class.path路径下的内容),用于提供JVM自身需要的类。

    ③、并不继承自java.lang.classLoader,没有父加载器。

    ④、加载扩展类和应用程序类加载器,并指定为他们的父类加载器。

    ⑤、出于安全考虑,Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类。

    1. import sun.misc.Launcher;
    2. import java.net.URL;
    3. import java.security.Provider;
    4. public class ClassLoaderTest01 {
    5. public static void main(String[] args) {
    6. System.out.println("--------启动类加载器--------");
    7. //获取BootstrapClassLoader加载下的api路径
    8. URL[] urLs = Launcher.getBootstrapClassPath().getURLs();
    9. for (URL url:urLs) {
    10. System.out.println("加载的路径为:" + url.toExternalForm());
    11. }
    12. //选择随意路径中的类,打印类加载器
    13. ClassLoader classLoader = Provider.class.getClassLoader();
    14. System.out.println(classLoader); //===>引导类加载器
    15. }
    16. }

    1.2、扩展类加载器(Extension classLoader)

    ①、Java语言编写,由sun.misc.Launcher$ExtClassLoader实现。

    ②、派生于classLoader类。

    ③、父类加载器为启动类加载器。

    ④、从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK的安装目录的jre/lib/ext子目录(扩展目录)下加载类库。如果用户创建的JAR放在此目录下,也会自动由扩展类加载器加载。

    1. public class ClassLoaderTest02 {
    2. public static void main(String[] args) {
    3. System.out.println("--------扩展类加载器--------");
    4. String property = System.getProperty("java.ext.dirs");
    5. for (String path:property.split(";")) {
    6. System.out.println("加载的路径为:" + path);
    7. }
    8. //选择随意路径中的类,打印类加载器
    9. ClassLoader classLoader = FormatData_aa.class.getClassLoader();
    10. System.out.println("类加载器类型:"+classLoader);//===》扩展类加载器
    11. }
    12. }

    1.3、应用程序类加载器(系统类加载器,AppclassLoader)

    ①、java语言编写,由sun.misc.Launcher$AppClassLoader实现。

    ②、派生于classLoader类。

    ③、父类加载器为扩展类加载器。

    ④、它负责加载环境变量classpath或系统属性java.class.path指定路径下的类库。

    ⑤、该类加载是程序中默认的类加载器,一般来说,Java应用的类都是由它来完成加载。

    ⑥、通过classLoader#getSystemClassLoader ()方法可以获取到类加载器。

    1.4、用户自定义类加载器

    1、在Java的日常应用程序开发中,类的加载几乎是由上述3种类加载器相互配合执行的,在必要时,我们还可以自定义类加载器,来定制类的加载方式。

    2、为什么要自定义类加载器:

    ①、隔离加载类。

    ②、修改类加载的方式。

    ③、扩展加载源。

    ④、防止源码泄露。

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

    ①、开发人员可以通过继承抽象类java.lang.ClassLoader类的方式,实现自己的类加载器,以满足一些特殊的需求。

    ②、在JDK1.2之前,在自定义类加载器时,总会去继承ClassLoader类并重写loadClass ()方法,从而实现自定义的类加载类,但是在JDK1.2之后已不再建议用户去覆盖loadClass ()方法,而是建议把自定义的类加载逻辑写在findClass()方法中。

    ③、在编写自定义类加载器时,如果没有太过于复杂的需求,可以直接继承URLClassLoader类,这样就可以避免自己去编写findClass ()方法及其获取字节码流的方式,使自定义类加载器编写更加简洁。

    参考代码:

    1. /**
    2. * 自定义用户类加载器
    3. */
    4. public class ClassLoaderTest03 extends ClassLoader {
    5. public static void main(String[] args) {
    6. ClassLoaderTest03 classLoaderTest03 = new ClassLoaderTest03();
    7. try {
    8. Class aClass = Class.forName("One", true, classLoaderTest03);
    9. Object o = aClass.newInstance();
    10. System.out.println(o.getClass().getClassLoader());
    11. }catch (Exception e){
    12. e.printStackTrace();
    13. }
    14. }
    15. @Override
    16. protected Class findClass(String name) throws ClassNotFoundException {
    17. try {
    18. byte[] result = getClassFromCustomPath(name);
    19. if (result == null){
    20. throw new FileNotFoundException();
    21. } else {
    22. return defineClass(name,result,0,result.length);
    23. }
    24. }catch (FileNotFoundException e){
    25. e.printStackTrace();
    26. }
    27. throw new ClassNotFoundException();
    28. }
    29. private byte[] getClassFromCustomPath(String name){
    30. //自定义路径中加载指定类,当指定路径的字节码文件进行了加密,就需要在本方法中进行解密操作。
    31. return null;
    32. }
    33. }

    二、ClassLoader

    ClassLoader类,它是一个抽象类,其后所有的类加载器都继承自ClassLoader(不包括启动类加载器)。

     结构图:

     sun.misc.Launcher是一个Java虚拟机的入口。

    2.1、获取ClassLoader的方法

    1、方式一:获取当前类的ClassLoader

    1. public class ClassLoaderTest04 {
    2. public static void main(String[] args) {
    3. try {
    4. ClassLoader classLoader1 = Class.forName("java.lang.String").getClassLoader();
    5. System.out.println("类加载器为:" + classLoader1);
    6. } catch (ClassNotFoundException e) {
    7. e.printStackTrace();
    8. }
    9. }
    10. }

    打印结果:

      2、方式二:获取当前线程上下文的ClassLoader

    1. public class ClassLoaderTest05 {
    2. public static void main(String[] args) {
    3. ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
    4. System.out.println("类加载器为:" + contextClassLoader);
    5. }
    6. }

    打印结果:

     3、方式三:获取系统的ClassLoader

    1. public class ClassLoaderTest06 {
    2. public static void main(String[] args) {
    3. ClassLoader parent = ClassLoader.getSystemClassLoader().getParent();
    4. System.out.println("类加载器为:" + parent);
    5. }
    6. }

    打印结果: 

     4、方式四:获取调用者的ClassLoader

  • 相关阅读:
    WSL 2 更改默认安装的 Linux 发行版
    Java新手小白入门篇 Java面向对象(七)
    【Linux--进程间通信】
    剑指 Offer 32 - I. 从上到下打印二叉树(java解题)
    浅谈数据和人工智能项目的管理
    第十四章 网络管理实战3
    ssh服务登录原理与配置
    这是一代骄马
    游戏史上五个定价最高的量产型游戏机
    (附源码)springboot手工diy网站 毕业设计 310226
  • 原文地址:https://blog.csdn.net/qq_46093575/article/details/126983311