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

自言自语

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

目录
相关文章
|
3月前
|
安全 前端开发 Java
【JVM的秘密揭秘】深入理解类加载器与双亲委派机制的奥秘!
【8月更文挑战第25天】在Java技术栈中,深入理解JVM类加载机制及其双亲委派模型是至关重要的。JVM类加载器作为运行时系统的关键组件,负责将字节码文件加载至内存并转换为可执行的数据结构。其采用层级结构,包括引导、扩展、应用及用户自定义类加载器,通过双亲委派机制协同工作,确保Java核心库的安全性与稳定性。本文通过解析类加载器的分类、双亲委派机制原理及示例代码,帮助读者全面掌握这一核心概念,为开发更安全高效的Java应用程序奠定基础。
92 0
|
2月前
|
安全 Java 应用服务中间件
JVM常见面试题(三):类加载器,双亲委派模型,类装载的执行过程
什么是类加载器,类加载器有哪些;什么是双亲委派模型,JVM为什么采用双亲委派机制,打破双亲委派机制;类装载的执行过程
JVM常见面试题(三):类加载器,双亲委派模型,类装载的执行过程
|
1月前
|
缓存 前端开发 Java
JVM知识体系学习二:ClassLoader 类加载器、类加载器层次、类过载过程之双亲委派机制、类加载范围、自定义类加载器、编译器、懒加载模式、打破双亲委派机制
这篇文章详细介绍了JVM中ClassLoader的工作原理,包括类加载器的层次结构、双亲委派机制、类加载过程、自定义类加载器的实现,以及如何打破双亲委派机制来实现热部署等功能。
46 3
|
2月前
|
Arthas Java 测试技术
JVM —— 类加载器的分类,双亲委派机制
类加载器的分类,双亲委派机制:启动类加载器、扩展类加载器、应用程序类加载器、自定义类加载器;JDK8及之前的版本,JDK9之后的版本;什么是双亲委派模型,双亲委派模型的作用,如何打破双亲委派机制
JVM —— 类加载器的分类,双亲委派机制
|
1月前
|
前端开发 Java 应用服务中间件
JVM进阶调优系列(1)类加载器原理一文讲透
本文详细介绍了JVM类加载机制。首先解释了类加载器的概念及其工作原理,接着阐述了四种类型的类加载器:启动类加载器、扩展类加载器、应用类加载器及用户自定义类加载器。文中重点讲解了双亲委派机制,包括其优点和缺点,并探讨了打破这一机制的方法。最后,通过Tomcat的实际应用示例,展示了如何通过自定义类加载器打破双亲委派机制,实现应用间的隔离。
|
6月前
|
前端开发 安全 Java
深入浅出JVM(八)之类加载器
深入浅出JVM(八)之类加载器
|
3月前
|
数据库 C# 开发者
WPF开发者必读:揭秘ADO.NET与Entity Framework数据库交互秘籍,轻松实现企业级应用!
【8月更文挑战第31天】在现代软件开发中,WPF 与数据库的交互对于构建企业级应用至关重要。本文介绍了如何利用 ADO.NET 和 Entity Framework 在 WPF 应用中访问和操作数据库。ADO.NET 是 .NET Framework 中用于访问各类数据库(如 SQL Server、MySQL 等)的类库;Entity Framework 则是一种 ORM 框架,支持面向对象的数据操作。文章通过示例展示了如何在 WPF 应用中集成这两种技术,提高开发效率。
60 0
|
3月前
|
开发者 C# Windows
WPF布局大揭秘:掌握布局技巧,轻松创建响应式用户界面,让你的应用程序更上一层楼!
【8月更文挑战第31天】在现代软件开发中,响应式用户界面至关重要。WPF(Windows Presentation Foundation)作为.NET框架的一部分,提供了丰富的布局控件和机制,便于创建可自动调整的UI。本文介绍WPF布局的基础概念与实现方法,包括`StackPanel`、`DockPanel`、`Grid`等控件的使用,并通过示例代码展示如何构建响应式布局。了解这些技巧有助于开发者优化用户体验,适应不同设备和屏幕尺寸。
94 0
|
3月前
|
安全 前端开发 Java
【JVM 探秘】ClassLoader 类加载器:揭秘 Java 类加载机制背后的秘密武器!
【8月更文挑战第25天】本文全面介绍了Java虚拟机(JVM)中的类加载器,它是JVM的核心组件之一,负责将Java类加载到运行环境中。文章首先概述了类加载器的基本工作原理及其遵循的双亲委派模型,确保了核心类库的安全与稳定。接着详细阐述了启动、扩展和应用三种主要类加载器的层次结构。并通过一个自定义类加载器的例子展示了如何从特定目录加载类。此外,还介绍了类加载器的完整生命周期,包括加载、链接和初始化三个阶段。最后强调了类加载器在版本隔离、安全性和灵活性方面的重要作用。深入理解类加载器对于掌握JVM内部机制至关重要。
157 0
|
4月前
|
存储 前端开发 Java
(二)JVM成神路之剖析Java类加载子系统、双亲委派机制及线程上下文类加载器
上篇《初识Java虚拟机》文章中曾提及到:我们所编写的Java代码经过编译之后,会生成对应的class字节码文件,而在程序启动时会通过类加载子系统将这些字节码文件先装载进内存,然后再交由执行引擎执行。本文中则会对Java虚拟机的类加载机制以及执行引擎进行全面分析。