JVM-类加载器 详解 值得您的阅读!!!

简介: JVM-类加载器 详解 值得您的阅读!!!

封面来源:微信公众号 杂乱无章--树熊

受多种情况的影响,又开始看JVM 方面的知识。

1、Java 实在过于内卷,没法不往深了学。

2、面试题问的多,被迫学习。

3、纯粹的好奇。 很喜欢一句话:“八小时内谋生活,八小时外谋发展。” --- 望别日与君相见时,君已有所成。 共勉

一、概述

Java类加载器(英语:Java Classloader)是Java运行时环境(Java Runtime Environment)的一部分,负责动态加载Java类到Java虚拟机的内存空间中。类通常是按需加载,即第一次使用该类时才加载。由于有了类加载器,Java运行时系统不需要知道文件与文件系统。

ClassLoader只负责class文件的加载,至于它是否可以运行,则由Execution Engine(执行引擎)决定。

==每个Java类必须由某个类加载器装入到内存。==

图示:

1704466435797.jpg

加载的类信息存放于一块称为方法区的内存空间。除了类的信息外,方法区中还会存放运行时常量池信息,可能还包括字符串字面量和数字常量(这部分常量信息是Class文件中常量池部分的内存映射)

二、类加载器的分类

JVM支持两种类型的类加载器 。分别为引导类加载器(Bootstrap ClassLoader)和自定义类加载器(User-Defined ClassLoader) 从概念上来讲,自定义类加载器一般指的是程序中由开发人员自定义的一类类加载器,但是Java虚拟机规范却没有这么定义,而是将所有派生于抽象类ClassLoader的类加载器都划分为自定义类加载器

类加载器结构图:

1704466452980.jpg

2.1、Bootstrap ClassLoader(根类加载器)

又可称之为 根类加载器、引导类加载器、启动类加载器,看到这些都要知道说的是 ==Bootstrap ClassLoader==。

  • 此类加载器是Java虚拟机的一部分,使用native代码(C++)编写。所以它是获取不到的
  • 加载位于/jre/lib目录中的或者被参数-Xbootclasspath所指定的目录下的核心Java类库。
  • 如图:1704466459598.jpg
  • 如上图:用来加载Java的核心库 ,rt.jar这个jar包就是Bootstrap根类加载器负责加载的,其中包含了java各种核心的类如java.lang,java.io,java.util,java.sql等 ,
  • Bootstrap ClassLoader 并不继承自java.lang.ClassLoader没有父加载器
  • 加载扩展类和应用程序类加载器,并作为他们的父类加载器(当他俩的爹)
  • Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类

代码测试:

public class BootstrapClassLoaderTest {
    public static void main(String[] args) {
        String s = new String();
        ClassLoader loader = s.getClass().getClassLoader();
        System.out.println("让我们一起来看看 String 是由加载的吧 ==>"+loader);
        //Bootstrap ClassLoader ==>null
        Integer integer = 2;
        ClassLoader classLoader1 = integer.getClass().getClassLoader();
        System.out.println("让我们一起来看看 Integer 是由加载的吧 "+classLoader1);
        //Bootstrap ClassLoader ==>null
    }
}

通过测试,我们可以发现全部都是 null ,其实 BootstrapClassLoader 我们是获取不到,它是由C++编写的。

测试小结:

我们可以证明,java、javax、sun等开头的类 的类确实是由启动类加载器加载的。 其他的大家也都可以试一试。

大家也会想,如果我们建项目时,也创建 一个java.lang 包,然后在底下写一个String类 或者写一个自定义类(MyUser)。启动类加载器会加载它吗?

答案:是什么???? 见文末。

2.2、Extension ClassLoader(扩展类加载器)

  • ClassLoader 的派生类
  • 父类加载器为启动类加载器(Bootstrap ClassLoader )
  • 用来在/jre/lib/ext,或java.ext.dirs中指明的目录中加载 Java的扩展库。
  • Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
  • 该类由sun.misc.Launcher$ExtClassLoader实现。
  • Java语言编写

环境要jdk 8 。 我的环境是 jdk11。所以底下代码是从 blog.csdn.net/sj158149630… 搬过来的。

代码测试:

public class ClassLoaderTest1 {
    public static void main(String[] args) {
        System.out.println("**********启动类加载器**************");
        //获取BootstrapClassLoader能够加载的api的路径
        URL[] urLs = sun.misc.Launcher.getBootstrapClassPath().getURLs();
        for (URL element : urLs) {
            System.out.println(element.toExternalForm());
        }
        //从上面的路径中随意选择一个类,来看看他的类加载器是什么:引导类加载器
        ClassLoader classLoader = Provider.class.getClassLoader();
        System.out.println(classLoader); //null
        System.out.println("***********扩展类加载器*************");
        String extDirs = System.getProperty("java.ext.dirs");
        for (String path : extDirs.split(";")) {
            System.out.println(path);
        }
        //从上面的路径中随意选择一个类,来看看他的类加载器是什么:扩展类加载器
        ClassLoader classLoader1 = CurveDB.class.getClassLoader();
        System.out.println(classLoader1);//sun.misc.Launcher$ExtClassLoader@1540e19d
    }
}

System.out.println(classLoader); //null 再次证明我们无法获取到启动类加载器

**********启动类加载器**************
file:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/resources.jar
file:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/rt.jar
file:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/sunrsasign.jar
file:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/jsse.jar
file:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/jce.jar
file:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/charsets.jar
file:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/jfr.jar
file:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/classes
null
***********扩展类加载器*************
/Users/xiexu/Library/Java/Extensions:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/jre/lib/ext:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java
sun.misc.Launcher$ExtClassLoader@d716361

2.3、AppClassLoader (应用程序类加载器 系统类加载器)

  • 同样是 Java 语言编写。
  • 由sun.misc.LaunchersAppClassLoader实现 (后有代码实现查看)
  • 派生于ClassLoader类
  • 该类加载是程序中默认的类加载器,一般来说,Java应用的类都是由它来完成加载
  • 通过classLoader.getSystemclassLoader()方法可以获取到该类加载器
  • 加载用户路径(ClassPath)上所指定的类库

代码测试:

public class AppClassLoaderTest {
    public static void main(String[] args) {
        BootstrapClassLoaderTest loaderTest = new BootstrapClassLoaderTest();
        ClassLoader classLoader = loaderTest.getClass().getClassLoader();
        System.out.println(classLoader);
        //jdk.internal.loader.ClassLoaders$AppClassLoader@2437c6dc 
    }
}

==小结==:所以一般来说,Java应用的类都是由它来完成加载

2.4、User-Defined ClassLoader (自定义类加载器)

可以通过继承java.lang.ClassLoader类的方式实现自己的类加载器,以满足一些特殊的需求而不需要完全了解Java虚拟机的类加载的细节。

可用于:

  • 运行时装载或卸载类。这常用于:
  • 实现脚本语言
  • 用于bean生成器
  • 允许用户定义的扩展性
  • 允许名字空间之间的通信。这是CORBA/RMI协议的基础。
  • 改变Java字节码的装入,例如,可用于Java类字节码的加密装入。)
  • 修改已装入的字节码weavingof aspects when usingaspect-oriented programming)。

2.5、关于ClassLoader类

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

如何获取到ClassLoader 呢?

总共有下面四种方式:

1、获取当前类的Classloader

2、获取当前线程上下文的ClassLoader

3、获取系统的ClassLoader

4、获取调用者的ClassLoader DriverManager.getCallerClassLoader()

public static void main(String[] args) {
    //1、获取当前类的ClassLoader
    BootstrapClassLoaderTest classLoaderTest = new BootstrapClassLoaderTest();
    ClassLoader classLoader = classLoaderTest.getClass().getClassLoader();
    System.out.println(classLoader);
    //2、获取当前线程上下文的ClassLoader
    new Thread(){
        @Override
        public void run() {
            System.out.println(Thread.currentThread());
            ClassLoader classLoader1 = Thread.currentThread().getContextClassLoader();
            System.out.println(classLoader);
        }
    }.run();
    //3、获取系统的ClassLoader
    ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
    System.out.println(systemClassLoader);
}

2.6、加载流程图

下图来自于:

1704466477131.jpg

四、答案

我也亲自去尝试了,全部都是报错。直接报 关于包的错误。创立String 类型也是一样的。

代码及结构:

1704466487341.jpg

错误:一、报的直接是说 此java程序包 已存在另一个模块中 。二、报启动类加载器 找不到。

1704466494676.jpg

自言自语

每天的焦虑生活,让人无比疲惫,却又无可奈何。

目录
相关文章
|
9月前
|
Arthas 测试技术
【面试题精讲】JVM-类加载器-使用Arthas查看类加载器
【面试题精讲】JVM-类加载器-使用Arthas查看类加载器
【面试题精讲】JVM-类加载器-使用Arthas查看类加载器
|
2月前
|
Java
jvm---类加载器(1)
jvm---类加载器(1)
|
2月前
|
前端开发 安全 Java
深入浅出JVM(八)之类加载器
深入浅出JVM(八)之类加载器
|
10天前
|
安全 前端开发 Java
《JVM由浅入深学习【一】 》JVM由简入深学习提升(类加载过程+父子类加载过程+类加载器+双亲委派机制)
《JVM由浅入深学习【一】 》JVM由简入深学习提升(类加载过程+父子类加载过程+类加载器+双亲委派机制)
9 0
|
2月前
|
监控 安全 Java
JVM工作原理与实战(九):类加载器-启动类加载器
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了启动类加载器、通过启动类加载器去加载用户jar包等内容。
47 8
|
2月前
|
监控 安全 Java
JVM工作原理与实战(十):类加载器-Java类加载器
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了扩展类加载器、通过扩展类加载器去加载用户jar包、应用程序类加载器等内容。
57 4
|
2月前
|
Arthas 安全 Java
JVM工作原理与实战(八):类加载器的分类
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了类加载器、类加载器的分类等内容。
36 4
|
2月前
|
监控 前端开发 安全
JVM工作原理与实战(十四):JDK9及之后的类加载器
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了JDK8及之前的类加载器、JDK9及之后的类加载器等内容。
58 2
|
2月前
|
监控 Java 关系型数据库
JVM工作原理与实战(十三):打破双亲委派机制-线程上下文类加载器
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了打破双亲委派机制的方法、线程上下文类加载器等内容。
47 2
|
2月前
|
监控 安全 前端开发
JVM工作原理与实战(十二):打破双亲委派机制-自定义类加载器
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了打破双亲委派机制的方法、自定义类加载器等内容。
27 1