首页 > 编程语言 >【java编程】Java 类加载器

【java编程】Java 类加载器

时间:2024-11-28 20:23:41浏览次数:6  
标签:java jar System println Java 加载 class out

jvm启动的时候, 并不会一次性加载所有的class文件, 而是根据需要去动态加载. 否则一次性加载那么多jar包那么多class, 那内存将崩溃.

Java 类加载器

Java 类加载流程

Java语言系统自带有三个类加载器, 分别为如下:
BootStrap ClassLoader

Bootstrap ClassLoader: 最顶层的加载类, 主要加载核心类库, %JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等,其中的rt.jar包中包含了java.lang, java.io等包, 所以我们可以直接在一个干净的java环境中进行引入FileInputStream, Integer, String类等, 如图:

当然, 我们也可以通过如下代码进行查看Bootstrap ClassLoader具体扫描了哪些包:

package com.heihu577;

public class HeihuHello {
    public static void main(String[] args) {
        ClassLoader classLoader = String.class.getClassLoader(); // 得到 String 这个类是由哪个 ClassLoader 加载的. 这里返回 null, 说明是被 BootStrap ClassLoader 所加载了, 我们在尝试获取被Bootstrap ClassLoader类加载器所加载的类的ClassLoader时候都会返回null。
        String searchPath = System.getProperty("sun.boot.class.path"); // sun.boot.class.path 是 bootstrap 所扫描包的路径
        System.out.println("当前扫描路径为: " + searchPath);
        /*
            当前扫描路径为: D:\SoftWare\Java8\jre\lib\resources.jar;D:\SoftWare\Java8\jre\lib\rt.jar;D:\SoftWare\Java8\jre\lib\sunrsasign.jar;D:\SoftWare\Java8\jre\lib\jsse.jar;D:\SoftWare\Java8\jre\lib\jce.jar;D:\SoftWare\Java8\jre\lib\charsets.jar;D:\SoftWare\Java8\jre\lib\jfr.jar;D:\SoftWare\Java8\jre\classes
        */
    }
}

当然了, 除了这个固定的扫描包的规则之外, 我们还可以通过-Xbootclasspath参数增加要扫描的包, -Xbootclasspath解释如下:

-Xbootclasspath:路径 指定的路径会完全取代jdk核心的搜索路径
-Xbootclasspath/a:路径 指定的路径会append(追加)在核心搜索路径之后
-Xbootclasspath/p:路径 指定的路径会prefix(之前)在核心搜索路径之后

测试这三种结果, 再测试一个没有增加该参数的情况:

通常都使用 /a 参数, 该扫描路径有一个先后顺序问题, 当前后两个jar包中, 存在两个相同包相同名称的类时, 先被扫描到的包下的类, 将被 JVM 解析.

Ext ClassLoader

扩展的类加载器,加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件。还可以加载-D java.ext.dirs选项指定的目录。

根据上面的案例, 我们进行如下操作:

随后准备如下代码:

package com.heihu577;

import org.apache.commons.dbutils.AbstractQueryRunner;

public class HeihuHello {
    public static void main(String[] args) {
        ClassLoader classLoader = AbstractQueryRunner.class.getClassLoader(); // 得到加载 AbstractQueryRunner 类的 ClassLoader
        System.out.println(classLoader); // sun.misc.Launcher$ExtClassLoader@29453f44
        String extDirs = System.getProperty("java.ext.dirs"); // ExtClassLoader 通过 java.ext.dirs 查看扫描路径
        System.out.println(extDirs); // D:\SoftWare\Java8\jre\lib\ext;C:\WINDOWS\Sun\Java\lib\ext
    }
}

可以看到, 此时classLoader则变为了ExtClassLoader所加载进来的, 当然, 我们也可以指明-D参数来修改ExtClassLoader扫描的路径, 如图:

注意: 这里图中应该改为配置dirs D:\BaiduNetdiskDownload\

最后运行结果:

sun.misc.Launcher$AppClassLoader@18b4aac2
D:\BaiduNetdiskDownload\

这种方式当然也不要随意用, 只是做环境测试.
App ClassLoader

这里我们App ClassLoader其实读取的就是我们的CLASSPATH, 当然也是我们IDEA中运行代码时所指明的参数, 准备如下代码:

public class HeihuHello {
    public static void main(String[] args) {
        ClassLoader classLoader = AbstractQueryRunner.class.getClassLoader();
        System.out.println(classLoader);
        String myClassPath = System.getProperty("java.class.path");
        System.out.println(myClassPath);
    }
}

运行结果 (包含命令行):

# 注意运行命令中的 -classpath 参数

D:\SoftWare\Java8\bin\java.exe "-javaagent:D:\SoftWare\IntelliJ IDEA 2023.2.1\lib\idea_rt.jar=8196:D:\SoftWare\IntelliJ IDEA 2023.2.1\bin" -Dfile.encoding=UTF-8 -classpath CLASSPATH值 com.heihu577.HeihuHello
# 运行结果
sun.misc.Launcher$AppClassLoader@18b4aac2
CLASSPATH值

进程已结束,退出代码为 0

当然了, AppClassLoader的父亲(不是父类)是ExtClassLoader:

public class HeihuHello {
    public static void main(String[] args) {
        ClassLoader classLoader = AbstractQueryRunner.class.getClassLoader();
        System.out.println(classLoader); // sun.misc.Launcher$AppClassLoader@18b4aac2
        System.out.println(classLoader.getParent()); // sun.misc.Launcher$ExtClassLoader@12a3a380
    }
}

理解完这三种 ClassLoader 后, 笔者在这里准备了一个本地脚本, 用来运行并理解每次clazz.getClassLoader的返回值:

package com.heihu577;
public class Main {
    public static void main(String[] args) throws ClassNotFoundException {
  System.out.println("================================BootStrapClassLoader================================");
        String envKey = "sun.boot.class.path";
        String envValue = System.getProperty(envKey);
        String bootStrapClassName = "java.lang.Integer"; // 默认在 lib\rt.jar 包中
        System.out.println(envKey + " => " + envValue); // 得到 BootStrap 加载的所有 jar 包
        System.out.println(bootStrapClassName + " => " + Class.forName(bootStrapClassName).getClassLoader()); // 因为是BootStrap加载, 所以这里应该返回 NULL
        System.out.println("--------------------------------运行时指明参数----------------------------------");
        System.out.println("-Xbootclasspath:路径 指定的路径会完全取代jdk核心的搜索路径\n" +
                "-Xbootclasspath/a:路径 指定的路径会append(追加)在核心搜索路径之后\n" +
                "-Xbootclasspath/p:路径 指定的路径会prefix(之前)在核心搜索路径之后");
        System.out.println("================================ExtClassLoader================================");
        envKey = "java.ext.dirs";
        envValue = System.getProperty(envKey);
        String extClassName = "com.sun.nio.zipfs.JarFileSystemProvider"; // 默认在 /lib/ext/zipfs 包中
        System.out.println(envKey + " => " + envValue);
        System.out.println(extClassName + " => " + Class.forName(extClassName).getClassLoader());
        // 因为是 ExtClassLoader 加载, 所以是 sun.misc.Launcher$ExtClassLoader
        System.out.println("--------------------------------运行时指明参数----------------------------------");
        System.out.println("-Djava.ext.dirs=目录");
        System.out.println("================================AppClassLoader================================");
        envKey = "java.class.path";
        envValue = System.getProperty(envKey);
        System.out.println(envKey + " => " + envValue);
        String appClassName = "lombok.Data";
        System.out.println(appClassName + " => " + Class.forName(appClassName).getClassLoader());
        /*
        * <dependencies>
            <dependency>
                <groupId>org.projectlombok</groupId>

                <artifactId>lombok</artifactId>

                <version>1.18.20</version>

            </dependency>

          </dependencies>

        * */
    }
}

接下来抛出一个问题, AppClassLoader, ExtClassLoader是如何被创建的?
Launcher

上面的代码可以看到, AppClassLoader, ExtClassLoader都是属于sun.misc.Launcher类中的一个成员类, 我们看一下Launcher类的具体操作如下:

标签:java,jar,System,println,Java,加载,class,out
From: https://www.cnblogs.com/o-O-oO/p/18575091

相关文章

  • 【java编程】Java 类 && Class 文件
    jvm启动的时候,并不会一次性加载所有的class文件,而是根据需要去动态加载.否则一次性加载那么多jar包那么多class,那内存将崩溃.Java类&&Class文件定义Heihu577.java文件,内容如下:publicclassHeihu577{publicstaticvoidmain(String[]args){Syst......
  • Java class 文件安全加密工具对比+ClassFinal实战
    前言常见加密方案对比XJarProGuardClassFinalClassFinal实战纯命令方式maven插件方式最后前言相信不少的同学开发的软件都是用户商业化,对于这些商业运营的项目很多都会直接部署在客户方,这样就可能会导致项目源码泄露。当然,作为Java语言的搬砖人......
  • Qt VTK加载openfoam计算结果
    QtVTK加载openfoam计算结果.foam文件。 #include<QApplication>#include<QDebug>#include"qvtkopenglwidget.h"#include<vtkSmartPointer.h>#include<vtkGenericDataObjectReader.h>#include<vtkPolyDataMapper.h>#include&......
  • Java 编程的经典反例及其事故分析
    Java编程的经典反例及其事故分析Java作为一种广泛使用的编程语言,凭借其稳定性和可移植性在众多领域中占据了重要地位。然而,即便是最强大的语言,也会因为不良的编程习惯而导致严重的事故。本文将列举几个经典的Java编程反例,并分析这些反例背后的原因及其可能带来的影响......
  • [2096]基于JAVA的混凝土供应链智慧管理系统的设计与实现
    毕业设计(论文)开题报告表姓名学院专业班级题目基于JAVA的混凝土供应链智慧管理系统的设计与实现指导老师(一)选题的背景和意义背景部分:在当今信息化高速发展的时代背景下,随着我国基础设施建设规模不断扩大,混凝土作为建筑行业不可或缺的基础材料,其供应链管理面临着巨大的......
  • [2093]基于JAVA的涉诉资产智慧管理系统的设计与实现
    毕业设计(论文)开题报告表姓名学院专业班级题目基于JAVA的涉诉资产智慧管理系统的设计与实现指导老师(一)选题的背景和意义选题背景:随着我国法治建设的不断深入和司法体系的日益完善,涉诉资产作为诉讼活动中的重要组成部分,其管理效率与公正性直接影响着司法工作的质量和效......
  • 揭秘Java反射的神秘面纱:Method.invoke方法,让你的代码更灵活!
    Java反射机制允许程序在运行时动态地访问和操作类的属性和方法。Method类的invoke方法是反射API中一个非常强大的工具,它可以用来调用任何对象的任意方法,包括私有方法。基本用法Method.invoke(Objectobj,Object...args)方法用于调用对象obj上的方法。其中,args是传递给......
  • 【Java 操作共享文件夹,SmbFile类让你轻松实现!】
    在Java中,通过使用SmbFile类可以方便地操作共享文件夹。SmbFile是JCIFS(JavaCIFSClientLibrary)库的一部分,用于访问基于SMB/CIFS协议的共享文件和打印机。以下是如何使用SmbFile类来操作共享文件夹的详细步骤和代码示例:1.添加JCIFS依赖首先,你需要在你的项目中添加JCI......
  • JAVA之多线程
    什么是线程?线程(Thread)是一个程序内部的一条执行流程。什么是多线程?多线程是指从软硬件上实现的多条执行流程的技术(多条线程由CPU负责调度执行)如何创建多线程:有两种方法可以创建新的执行线程。一种是将类声明为Thread的子类。此子类应覆盖类Thread的run方法。然后可......
  • 深入理解 Java 虚拟机-第一部分 走进 Java 笔记
    Sun/Oracle公司研发的热门虚拟机有三个:ClassicVM/ExactVM/HotSpotVMClassicVM:基于句柄(Handle)的对象查找方式,需要外挂JITExactVM:优于ClassicVM,使用了准确式内存管理(记录内存中存储的类型是地址还是数值),丢弃句柄,内置JIT,支持热点代码探测(通过计数器找出有......