首页 > 其他分享 >jvm 类加载

jvm 类加载

时间:2023-04-14 10:35:01浏览次数:42  
标签:java name 自定义 ClassLoader jvm byte 加载

将字节码文件加载到 jvm,并创建对应的字节码对象,然后对其进行验证、初始化等操作
共 5 个阶段:加载、验证、准备、解析、初始化,这里只记录【加载】里的类加载器和双亲委派

加载的是字节码文件

通过类加载器 ClassLoader 把字节码文件在堆中生成代表这个 class 文件的 java.lang.Class 对象

ClassLoader 分类

  • 站在虚拟机角度分为两种:启动类加载器(c++实现,虚拟机的一部分)、其他类加载器(java实现,java.lang.ClassLoader 的字类)
  • 站在开发角度可以分为 4 种启动类加载器、扩展类加载器、应用程序类加载器、自定义类加载器

各种 ClassLoader

  • 启动类加载器(Bootstrap ClassLoader)
    • 加载 java 核心类库,JAVA_HOME/lib 目录下的类库或 -Xbootclasspath 参数指定路径的类库
    • 处于安全考虑只加载 java、javax、sun 开头的类
    • 没有父加载器
  • 扩展类加载器(Extension ClassLoader)
    • 加载 JAVA_HOME/lib/ext 目录中的类库
    • 父加载器是 Boostrap ClassLoader
  • 应用程序类加载器(Application ClassLoader)
    • 加载我们自己编写的类
    • 父加载器是 Extention ClassLoader
  • 自定义类加载器(Customer ClassLoader)
    • 继承 java.net.URLClassLoader 或 java.lang.ClassLoader类,重写 findClass,如果要打破双亲委派机制需要重写 loadlass 方法
    • 加载自己指定路径的class文件
    • 父加载器是 Application ClassLoader

双亲委派

  • 目的是保证类的唯一性和安全性
  • 比如我们自定义一个 java.lang 包,然后创建 String 类,jdk 本身也存在 java.lang.String 类,显然是有问题的
  • 具体是:加载器收到一个类的加载请求,不管自己能不能加载都让父类加载器加载,直到引导类加载器
  • 如果引导类加载器加载不了,扩展类加载器加载;如果还是加载不了,应用类加载器尝试加载;如果还加载不了,说明没这个类抛出 ClassNotFound 异常或让自定义类加载器加载

类加载方式

  • 隐式加载
    • 遇到 new,或者获取静态变量等时
    • 对类进行反射调用时
    • 虚拟机启动时,加载包含 main 方法的主类
  • 显式加载
    • Class.forName(): 将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块
    • ClassLoader.loadClass(): 只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块
    • Class.forName(name, initialize, loader)带参函数也可控制是否加载static块。并且只有调用了newInstance()方法采用调用构造函数,创建类的对象

自定义类加载器

除了BootstrapClassLoader是由C/C++实现的,其他的类加载器都是ClassLoader的子类。所以如果我们想实现自定义的类加载器,首先要继承ClassLoader

  • 如果不想打破双亲委派机制,那么只需要重写findClass方法
  • 如果想要打破双亲委派机制,那么就需要重写整个loadClass方法

自定义类加载器

public class MyClassLoader extends ClassLoader{
    //默认ApplicationClassLoader为父类加载器
    public MyClassLoader(){
        super();
    }

    //加载类的路径
    private String path = "";

    //重写findClass,调用defineClass,将代表类的字节码数组转换为Class对象
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] dataByte = new byte[0];
        try {
            dataByte = ClassDataByByte(name);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return this.defineClass(name, dataByte, 0, dataByte.length);
    }

    //读取Class文件作为二进制流放入byte数组, findClass内部需要加载字节码文件的byte数组
    private byte[] ClassDataByByte(String name) throws IOException {
        InputStream is = null;
        byte[] data = null;
        ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
        name = name.replace(".", "/"); // 为了定位class文件的位置,将包名的.替换为/
        is = new FileInputStream(new File(path + name + ".class"));
        int c = 0;
        while (-1 != (c = is.read())) { //读取class文件,并写入byte数组输出流
            arrayOutputStream.write(c);
        }
        data = arrayOutputStream.toByteArray(); //将输出流中的字节码转换为byte数组
        is.close();
        arrayOutputStream.close();
        return data;
    }
}

使用自定义类加载器加载指定的类

public static void main(String[] args) {
    MyClassLoader myClassLoader = new MyClassLoader();
    Class<?> clazz = myClassLoader.loadClass("com.fengjian.www.MyClassLoader");
    clazz.newInstance();
}

标签:java,name,自定义,ClassLoader,jvm,byte,加载
From: https://www.cnblogs.com/hangychn/p/17317541.html

相关文章

  • jvm 字节码
    编译前端编译:依靠jdk的编译工具把java文件编译成class文件,javac命令后端编译:class文件编译成机器指令逐行读取class文件内同,并解释成机器指令引入jit技术提高解释效率,比如某些类中共有的内容,这些内容解释次数过多就直接缓存起来反编译:把class文件反编译为......
  • jvm 初识
    总结jvm是一套规范,只要实现了相关规定就可以视为是一个jvm,jdk的是hotSpot,不同jdk版本的jvm也有细微差异jvm不仅可以作为java的运行环境,还能作为别的语言的运行环境,比如kotlin、groovy等java能跨平台是因为不同平台都有对应的jvm,jvm能把同样的java文件生成......
  • jvm
    1.什么情况下会发生栈内存溢出。  2.详解JVM内存模型思路:给面试官画一下JVM内存模型图,并描述每个模块的定义,作用,以及可能会存在的问题,如栈溢出等。我的答案:JVM内存结构   3.JVM内存为什么要分成新生代,老年代,持久代。新生代中为什么要分为Eden和Survivor。4.JVM......
  • JVM:内存结构上
    !点击代码高亮化!jvm内存结构·上程序计数器虚拟机栈(线程私有栈-方法的栈帧\FILO)当前线程的压入的方法的栈帧-Xss"SIZE":设置线程栈大小栈内存溢出SO:StackOverflowErrorat'错误代码处'递归调用有时第三方库也会导致SO:ObjectMapper/@JsonIgnore线程安全方法的......
  • 【异步加载JS脚本(script标签)至html文档中】的辅助函数
    Code:/***'asyncLoadScript'方法的配置项'options'的类型定义*@typedef{Object}IOptions*@prop{string}id-script标签的ID*@prop{Function}onSucceed-加载成功后的回调*@prop{(Function|undefined)}onFailed-加载失败后的回调*@prop{boolean}s......
  • 取消加载项提升Office软件打开速度的方法
      本文介绍基于修改加载项,解决MicrosoftOffice系列软件开启速度较慢的办法。  最近,发现Excel软件的打开速度越来越慢,会在一定程度上影响工作效率。因此尝试对此加以解决。其中,本文所给方法对于Word/Excel/PPT文件均适用。但请注意,本文所给出的解决方法仅对由于加载项过多造成......
  • jvm
    java内存模型与分区:本地方法栈:native方法调用本地其他语言接口;程序计数器:记录当前线程的运行位置;栈:存放运行时的方法,包括:局部变量表、操作数栈、动态链接(指向常量池)和方法返回地址。堆:初始化的对象、成员变量。方法区:类型信息(加载类的类型(Class)、类的完整名称、类型修饰符等......
  • 手机直播源码,JS实现页面下拉加载数据操作
    手机直播源码,JS实现页面下拉加载数据操作主要是在id="ph"的div内加载数据: <!DOCTYPEhtmlPUBLIC"-//W3C//DTDXHTML1.0Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><htmlxmlns="http://www.w3.org/1999/xhtml&qu......
  • JVM 内存
    简述JVM内存模型  从宏观上来说JVM内存区域分为三部分线程共享区域、线程私有区域、直接内存区域。1.1、线程共享区域1.1.1、堆区堆区Heap是JVM中最大的一块内存区域,基本上所有的对象实例都是在堆上分配空间。堆区细分为年轻代和老年代,其中年轻代又分为Eden、S0、S1......
  • Cesium如何加载PBS发布的WMTS服务
    Cesium加载Geoserver发布的WMTS服务,url示例:'http://localhost:8080/geoserver/gwc/service/wmts/rest/nurc:mosaic/{style}/{TileMatrixSet}/{TileMatrix}/{TileRow}/{TileCol}?format=image/png',而PBS(PortableBasemapServer)发布的地址是这样:http://192.168.58.1:7080/PBS/re......