JVM类加载器ClassLoader

Java Classloader是Java Runtime Environment的一部分,负责动态加载Java字节码文件到Java虚拟机的内存空间中。

类加载过程
加载
  1. 通过类的全限定名来获取该类的二进制字节流
  2. 把二进制字节流转化为方法区的运行时数据结构
  3. 在堆上创建一个java.lang.Class对象,用来封装类在方法区数据结构,并向外提供访问方法区内部数据结构的接口
加载方式
  1. 从本地文件系统、jar等归档文件中加载
  2. 将Java源文件动态编译为class
  3. 网络下载、从专有数据库中加载等
验证

校验字节码文件的正确性

准备

给类的静态变量分配内存,并赋予默认值

解析

将常量池中的符号引用转换为直接引用

初始化

对类的静态变量初始化为指定的值,执行静态代码块

使用
卸载
类加载器类型
启动类加载器

BootstrapClassLoader, 用于加载启动基础模块类,负载加载支撑JVM运行的位于JRE的lib目录下的核心类库,比如rt.jar、charsets.jar等

扩展类加载器

ExtClassLoader, 负责加载支撑JVM运行的位于JRE的lib目录下的ext扩展目录中的JAR类包

平台类加载器

PlatformClassLoader, JDK8之后替换了扩展类加载器

应用程序类加载器

AppClassLoader, 负责加载ClassPath路径下的类包,主要就是加载你自己写的那些类

自定义类加载器

负责加载用户自定义路径下的类包,java.lang.ClassLoader的子类

类加载器的关系

启动类加载器->平台类加载器或扩展类加载器->应用程序类加载器->自定义类加载器,前者是后者的父级

双亲委派机制

双亲委派机制说简单点就是,先找父亲加载,不行再由儿子自己加载

为什么需要双亲委派机制?

  1. 沙箱安全机制:自己写的java.lang.String.class类不会被加载,这样便可以防止核心API库被随意篡改
  2. 避免类的重复加载:当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次,保证被加载类的唯一性
class ClassLoaderTest {
    public static void main(String[] args) {

        //null,启动类加载器是C++语言实现,所以打印不出来
        System.out.println(String.class.getClassLoader());

        //sun.misc.Launcher$ExtClassLoader@1b28cdfa
        System.out.println(com.sun.crypto.provider.DESKeyFactory.class.getClassLoader());

        //sun.misc.Launcher$AppClassLoader@18b4aac2
        System.out.println(ClassLoaderTest.class.getClassLoader());

        System.out.println("");
        //sun.misc.Launcher$ExtClassLoader
        System.out.println(MyClassLoader.class.getClassLoader().getParent());
        //null
        System.out.println(MyClassLoader.class.getClassLoader().getParent().getParent());
    }
}

/**
 * 自定义ClassLoader
 */
class MyClassLoader extends ClassLoader{
    private String name;

    public MyClassLoader(String name) {
        this.name = name;
    }

    /*
     * 重写findClass方法
     */ 
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] data = loadData(name);
        return this.defineClass(name, data, 0, data.length);
    }

    /*
     * 自定义类加载器去classes下找对应的字节码文件
     */ 
    private byte[] loadData(String name) {

        name = name.replace(".", "/");
        String clazzFilePath = "classes/" + name + ".class";
        byte[] data = null;
        InputStream in = null;
        ByteArrayOutputStream out = new ByteArrayOutputStream();

        try {
            in = new FileInputStream(new File(clazzFilePath));
            int a = 0;
            while ((a = in.read()) != -1){
                out.write(a);
            }
            data = out.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return data;
    }

}

class Person {
}

/*
 * 1.直接测试, 输出sun.misc.Launcher$AppClassLoader@18b4aac2
 * 2.移动out/production/java/com/example/jvm/loader/Person.class到classes/com/example/jvm/loader/Person.class
 * 3.再次运行输出com.example.jvm.loader.MyClassLoader@74a14482,使用了我们自定义的类加载器
 */ 
class MyClassLoaderTest {
    public static void main(String[] args) throws ClassNotFoundException {
        MyClassLoader myClassLoader = new MyClassLoader("MyClassLoader");
        Class aClass = myClassLoader.loadClass("com.example.jvm.loader.Person");
        System.out.println(aClass.getClassLoader());
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值