【JAVA】类加载

1.概述

类加载器是用来加载 Class 的,将 Class 的字节码形式转换成内存形式的 Class 对象。字节码可以来自于磁盘文件 *.class,也可以是 jar 包里的 *.class,也可以来自远程服务器提供的字节流,字节码的本质就是一个字节数组 byte[],它有特定的复杂的内部格式。

类的唯一性

每个 Class 对象的内部都有一个 classLoader 字段来标识自己是由哪个 ClassLoader 加载的。类的唯一性是由类加载器实例以及类的全名一同确定的。即便是同一串字节流,经由不同的类加载器加载,也会得到两个不同的类。

2.双亲委派机制

在这里插入图片描述

⑴类加载器介绍
①启动类加载器

启动类加载器负责加载最为基础、最为重要的类,比如存放在 JRE 的 lib 目录下 jar 包中的类(以及由虚拟机参数 -Xbootclasspath 指定的类),我们常用内置库 java.xxx.* 都在里面,比如 java.util.、java.io.、java.nio.、java.lang. 等等,程序无法对其进行任何操作。启动类加载器是由C++实现,没有对应的JAVA对象,在JAVA中由NULL指代。

②扩展类加载器

ExtClassLoader,负责加载<Java_Home>/lib/ext或者由系统变量-Djava.ext.dir指定位置中的类库。程序可以访问并使用扩展类加载器。

③系统类加载器(应用程序加载器)

AppClassLoader,系统类加载器是由sun.misc.Launcher.AppClassLoader实现的,负责加载系统类路径-classpath或-Djava.class.path变量所指的目录下的类库。程序可以访问并使用系统类加载器,我们自己编写的代码以及使用的第三方 jar 包通常都是由它来加载的。

⑵类加载器初始化过程

在虚拟机启动的时候会初始化BootstrapClassLoader,然后在Launcher类中去加载ExtClassLoader、AppClassLoader,并将AppClassLoader的parent设置为ExtClassLoader,并设置线程上下文类加载器。
Launcher是JRE中用于启动程序入口main()的类:

public Launcher() {
        Launcher.ExtClassLoader var1;
        try {
            //加载扩展类类加载器
            var1 = Launcher.ExtClassLoader.getExtClassLoader();
        } catch (IOException var10) {
            throw new InternalError("Could not create extension class loader", var10);
        }

        try {
            //加载应用程序类加载器,并设置parent为extClassLoader
            this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
        } catch (IOException var9) {
            throw new InternalError("Could not create application class loader", var9);
        }
        //设置默认的线程上下文类加载器为AppClassLoader
        Thread.currentThread().setContextClassLoader(this.loader);
        //此处删除无关代码。。。
        }
⑶双亲委派模型的好处

双亲委派模型能保证基础类仅加载一次,不会让jvm中存在重名的类。比如String.class,每次加载都委托给父加载器,最终都是BootstrapClassLoader,都保证java核心类都是BootstrapClassLoader加载的,保证了java的安全与稳定性。

⑷类加载器的三个重要方法
①loadClass

它首先会查找当前 ClassLoader 以及它的双亲里面是否已经加载了目标类,如果没有找到就会让双亲尝试加载,如果双亲都加载不了,就会调用 findClass() 让自定义加载器自己来加载目标类。

②findClass

这个是需要覆盖的,不同的加载器将使用不同的逻辑来获取目标类的字节码

③defineClass

将字节码转换成 Class 对象

3.线程上下文加载器

线程上下文加载器,它不是一个新的类型,更像一个类加载器的角色,ThreadContextClassLoader可以是上述类加载器的任意一种,但往往是AppClassLoader。

没有设置则继承父线程(比如new Thread()方式),默认是系统类加载器(AppClassLoader)。

使用线程上下文加载类,也要注意保证多个需要通信的线程间的类加载器应该是同一个,防止因为不同的类加载器导致类型转换异常(ClassCastException)

4.URLClassLoader

该类加载器用于从一组URL路径(指向JAR包或目录)中加载类和资源。约定使用以 ‘/’结束的URL来表示目录。如果不是以该字符结束,则认为该URL指向一个JAR文件。
AppClassLoader、ExtClassLoader都是URLClassLoader的子类,自定义类加载器推荐直接继承它。

5.自己实现ClassLoader

自己实现ClassLoader时只需要继承ClassLoader类,然后覆盖findClass(String name)方法即可完成一个带有双亲委派模型的类加载器。parent需要自己设置。
另外AppClassLoader和ExtClassLoader不能继承。
最好将父加载器通过子类构造函数传入

protected ClassLoader(String name, ClassLoader parent);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值