首页 > 编程语言 >Java(2)-粗解类加载器

Java(2)-粗解类加载器

时间:2024-04-27 20:00:27浏览次数:21  
标签:Java 字节 粗解类 ClassLoader class public 加载

Java的类加载器是Java运行时环境中的重要组件,核心功能是将类的字节码加载到Java虚拟机中。

举个例子

可以通过一个图书馆的比喻来形象地解释类加载器的作用、用法和使用场景。
想象一下,有一个巨大的图书馆(JVM),其中有非常多的藏书()。当你(程序)需要阅读一本书(使用一个类)时,你首先需要找到这本书。这就是类加载器的职责:找到这些类的字节码,并将它们带到图书馆(JVM)中,使其可以被使用。

类加载器的分类

在 Java 中,类加载器大体可以分为三种:

  1. 引导类加载器(Bootstrap ClassLoader)
    这是最顶层的加载器,负责加载 Java 核心库(如 java.lang.* 等)。你可以把它看作是图书馆的基础藏书区,这里存放的都是一些最基本、最常用的书籍。
  2. 扩展类加载器(Extension ClassLoader)
    它负责加载 Java 扩展库,位于 jre/lib/ext 目录或者由 java 系统属性 java.ext.dirs 指定路径中的类库。想象这是图书馆的特殊资源区,比基础藏书区的书籍更专业,但不是每个人都需要。
  3. 应用程序类加载器(Application ClassLoader)
    这是加载你自己的代码和你使用的第三方库的类加载器。可以视作图书馆的普通藏书区,这里放着大量由各种出版社出版的各类书籍。

代码示例

理论差不多了,下面用代码对类加载器进行展开。

  1. 这是获取类加载器的一段代码
public class ClassLoaderExp {  
    public static void main(String[] args) {  
        ClassLoader classLoader = ClassLoaderExp.class.getClassLoader();  
        System.out.println(classLoader);  
    }  
}

输出结果是 jdk.internal.loader.ClassLoaders$AppClassLoader@63947c6b ,这个结果是 Java 类加载器实例的一个默认 toString() 方法的结果(备注,此代码是运行在JDK17上,如果采用其他版本JDK可能会有区别)。这里面包含了几部分信息:
(1)类加载器的类型jdk.internal.loader.ClassLoaders$AppClassLoader 指示这是 Java 内部使用的应用程序类加载器(Application ClassLoader),它是用来加载你的应用程序中的类(包括第三方库)的。
(2)实例标识符@63947c6b 是这个特定实例的哈希码,这是 JVM 在运行时为对象分配的一个标识符。
2. 我们也可以查看系统自带的类的类加载器

public class ClassLoaderExp {  
    public static void main(String[] args) {  
        ClassLoader classLoader  = Integer.class.getClassLoader();  
        System.out.println(classLoader);  
    }  
}

输出结果是 null,这是因为引导类加载器是C++写的,所以虽然输出null,但是可以默认它是引导类加载器(Bootstrap ClassLoader)。
3. 我们也可以自定义类加载器,可以从指定的文件路径加载类,这在需要从非标准源加载类(网络、加密文件等)时很有用。

public class CustomClassLoader extends ClassLoader {  
    @Override  
    // findaClass是用于查找类的方法,如果不重写这个方法,那么默认会调用父类的findClass方法  
    protected Class<?> findClass(String name) throws ClassNotFoundException {  
        byte[] classData = loadClassFromFile(name); // loadClassFromFile 方法是自定义的,用于从文件中读取类的字节码  
        /**  
         * defineClass() 方法是 ClassLoader 类的一个非常重要的方法,它用于将字节码数组转换成 Class 类的一个实例  
         * name 是类的全限定名,如 com.example.MyClass  
         * classData 是类的字节码数组  
         * 0 是字节码数组的起始位置  
         * classData.length 是字节码数组的长度  
         */  
        return defineClass(name, classData, 0, classData.length);  
    }  
  
    /**  
     * 根据类的名字加载类文件的字节码  
     * File.separatorChar是文件分隔符  
     * 这是因为在文件系统中,Java 的全类名(如 com.example.MyClass)需要转换为目录结构的路径(如 com/example/MyClass)  
     */  
    private byte[] loadClassFromFile(String fileName) {  
        InputStream resourceAsStream = getClass()  
                .getClassLoader()  
                .getResourceAsStream(fileName.replace('.', File.separatorChar) + ".class");  
        byte[] buffer;  
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();  
        int nextValue = 0;  
        try {  
            while ((nextValue = resourceAsStream.read()) != -1) {  
                byteArrayOutputStream.write(nextValue);  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        buffer = byteArrayOutputStream.toByteArray();  
        return buffer;  
    }  
}

使用代码:

public class ClassLoaderExp {  
    public static void main(String[] args) {  
        CustomClassLoader customClassLoader = new CustomClassLoader();  
        try {  
            Class<?> clazz = customClassLoader.loadClass("com.example.proxy2.Car"); // 这是随便写的一个类  
            Object obj = clazz.newInstance();  
            System.out.println(obj.getClass().getClassLoader());  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
}

输出:jdk.internal.loader.ClassLoaders$AppClassLoader@63947c6b

类加载器的使用场景

  1. 隔离加载: 在大型应用中,可能需要加载来自不同来源的相同名称的类,这时候类加载器可以通过不同的命名空间来实现类的隔离,防止命名冲突。就像图书馆中,可能有几本同名的书,但它们的作者或版本不同。
  2. 热替换和代码热部署: 在服务器运行时,你可能想要更新或替换某些类而不停机。使用自定义的类加载器可以在不重启应用的情况下重新加载修改过的类,就像图书馆在不关闭的情况下,替换掉某些旧书籍或者加入新书。
  3. 加密和解密: 出于安全考虑,可以使用自定义的类加载器来对类的字节码进行加密。当使用这些类时,通过类加载器对其进行解密后加载到 JVM 中,确保字节码在磁盘上的安全,类似于对图书馆中某些珍贵书籍进行加密保护。

标签:Java,字节,粗解类,ClassLoader,class,public,加载
From: https://www.cnblogs.com/marigo/p/18162425

相关文章

  • 学习笔记-Java内存区域
    Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外的人想进去,墙里面的人想出来。运行时数据区域Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域有各自的用途,以及创建和销毁的时间。有的区域随着虚拟机进程启动一直......
  • 【Java】java1.8安装教程及java环境配置
    一、下载JDK源文件1、根据自己系统,下载对应的文件下载地址:Java存档下载-JavaSE8u211及更高版本|Oracle中国 2、下载后,可将安装包移动到自定义目录中,然后双击文件进行安装操作 二、安装1、双击安装文件,根据安装向导指引,点击下一步,进行安装 2、点击下一步后,根......
  • java发送http请求
    privatevoidhandleCartItems(List<CartVO>vos){//1.获取商品idSet<Long>itemIds=vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());//2.查询商品ResponseEntity<List<ItemDTO>>response......
  • 在JavaScript中,DOM对象与jQuery对象的区别与转换
    Dom原生对象和jQuery对象的区别:jQuery选择器得到的jQuery对象和标准的js中的document.getElementById()取得的dom对象是两种不同类型,两者不等价。注:js原生获取的dom是一个对象;jQuery对象就是一个数组对象。JQuery无法使用DOM对象的任何方法,同样的DOM对象也不能使用JQuery里......
  • Java读取网址信息
    Java读取网址信息今天的需求是根据接口获取JSON数据并存入,之前只会前端用Ajax或者Axios去处理显示出来没想过后端也要拿,没有思路于是查找,发现都是基础以前用的还是太少了,特此总结,后续有需要再补充。1.读取get请求,无需参数publicstaticStringget(StringurlStr){//......
  • 微服务想缓存一些数据,不希望重复调用。java SoftReference软引用存储缓存
    背景:微服务我们要调用字典数据,但是很多都是要重复调用的,没有缓存,我为了设置一个应用的缓存,并且可以定时清理,更新 首先定义两个静态数据,。一个软连接缓存,一个定时清理线程privatestaticSoftReference<Map<String,Map<String,DictionaryVo>>>plmDicMapCache=newSoftR......
  • AssemblyResolve巧解未能加载文件或程序集“Newtonsoft.Json, Version=6.0.0.0的问题
    问题:未能加载文件或程序集“Newtonsoft.Json,Version=6.0.0.0,Culture=neutral,PublicKeyToken=30ad4fe6b2a6aeed”或它的某一个...问题分析:原因是因为引用的Microsoft.AspNet.SignalR.Client库的依赖项是6.0版本的Newtonsoft.Json,而且是动态加载进去的(用Assembly.LoadFrom),......
  • Java面向对象03——三大特性之继承
    一、继承(extends)1.1、继承是什么继承就是Java允许我们用extends关键字,让一个类与另一个类建立起一种父子关系;被继承的类称为父类(基类、超类),继承父类的类都称为子类(派生类) ,当子类继承父类后,就可以直接使用父类公共的属性和方法了当子类继承父类后,就可以直接使用父类公共的......
  • kali 设置 Java 版本,并更换为 1.8 版本
    kali设置Java版本,并更换为1.8版本1.安装JDK1.下载java1.8:https://repo.huaweicloud.com/java/jdk/8u202-b08/jdk-8u202-linux-x64.tar.gz2.建立目录,将下载的jdk的安装包复制过去并进行解压sudomkdir-p/usr/local/javacpjdk-8u202-linux-x64.tar.gz/usr/l......
  • openharmony 多线程的方式有哪些?两个worker线程数据如何通讯、内存如何共享、与Java多
    OpenHarmony操作系统支持多种多线程并发处理策略,以提升应用的响应速度与帧率,以及防止耗时任务对主线程的干扰。以下是OpenHarmony中的多线程方式,以及Worker线程间的数据通讯和内存共享方法,还有它们与Java多线程的区别:OpenHarmony多线程方式Worker线程:OpenHarmony中的Worker是......