再谈类的加载器

概述

类加载器是JVM执行类加载机制的前提。

ClassLoader的作用:

ClassLoader是Java的核心组件,所有的Class都是由ClassLoader进行加载的,ClassLoader负责通过各种方式将Class信息的二进制数据流读入JVM内部,转换为一个与目标类对应的java.lang.Class对象实例。然后交给Java虚拟机进行链接、初始化等操作。因此,ClassLoader在整个装载阶段,只能影响到类的加载,而无法通过ClassLoader去改变类的链接和初始化行为。至于它是否可以运行,则由Execution Engine决定。

在这里插入图片描述

1-大厂面试题

在这里插入图片描述
在这里插入图片描述

2-类加载器的分类

在这里插入图片描述

3-类加载器的必要性

在这里插入图片描述

4-命名空间

在这里插入图片描述
代码解释:
在这里插入图片描述

结果:在这里插入图片描述
解释:
rootDir后面的地址是我们使用javac User.class指令生成的class文件地址,然后loader1和loader2是两个用户自定义类加载器(如果自定义的不必理解),之后使用这两个用户自定义类加载器加载同一类型的User类,获得的Class对象不是同一个,可以通过Class对象调用getClassLoader()方法获取对应的类加载器了,最后通过系统类加载器获取的Class对象也是独特的,也可以通过该Class对象获取系统类加载器

5-类加载机制的基本特征

在这里插入图片描述

6-类加载器之间的关系
Launcher.java类:
public class Launcher {
    ……

    public Launcher() {
        Launcher.ExtClassLoader var1;
        try {
            var1 = Launcher.ExtClassLoader.getExtClassLoader();
        } catch (IOException var10) {
            throw new InternalError("Could not create extension class loader", var10);
        }

        try {
            this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
        } catch (IOException var9) {
            throw new InternalError("Could not create application class loader", var9);
        }

        Thread.currentThread().setContextClassLoader(this.loader);
                ……
}

分析:
1、验证扩展类加载器的父类是null
先看:
 var1 = Launcher.ExtClassLoader.getExtClassLoader();
获取到扩展类加载器,点击该方法往里面追溯,在找到:
return new Launcher.ExtClassLoader(var0);
我们在点击该方法往里面追溯,在找到:
super(getExtURLs(var1), (ClassLoader)null, Launcher.factory);
然后点击super,往里面追溯,在找到:
public URLClassLoader(URL[] urls, ClassLoader parent,
                      URLStreamHandlerFactory factory) {
    super(parent);
点击其中的parent就是null,我们点击super,往里面追溯,在找到:
protected SecureClassLoader(ClassLoader parent) {
    super(parent);
点击其中的parent就是null,我们点击super,往里面追溯,在找到:
protected ClassLoader(ClassLoader parent) {
    this(checkCreateClassLoader(), parent);
}
点击其中的parent就是null,我们点击this,往里面追溯,在找到:
private ClassLoader(Void unused, ClassLoader parent) {
    this.parent = parent;
由于parent就是null,所以扩展类加载器的父类是null,也就是引导类加载器,因此我们调用获取扩展类加载器父类的方法获得的结果是null

2、验证系统类加载器的父类是扩展类加载器
先看:
this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
获取到系统类加载器,点击该方法往里面追溯,在找到:
return new Launcher.AppClassLoader(var1x, var0); 
其中var0就是扩展类加载器,点击AppClassLoader,往里面追溯,在找到:
AppClassLoader(URL[] var1, ClassLoader var2) {
    super(var1, var2, Launcher.factory);
    this.ucp.initLookupCache(this);
}
其中var2就是扩展类加载器,我们点击super,往里面追溯,在找到:
public URLClassLoader(URL[] urls, ClassLoader parent,
                      URLStreamHandlerFactory factory) {
    super(parent);
里面的parent就是扩展类加载器,我们点击super,往里面追溯,在找到:
protected SecureClassLoader(ClassLoader parent) {
    super(parent);
里面的parent就是扩展类加载器,我们点击super,往里面追溯,在找到:
protected ClassLoader(ClassLoader parent) {
    this(checkCreateClassLoader(), parent);
}
里面的parent就是扩展类加载器,我们点击this,往里面追溯,在找到:
private ClassLoader(Void unused, ClassLoader parent) {
    this.parent = parent;
由于parent就是扩展类加载器,所以系统类加载器的父类是扩展类加载器,因此我们调用获取系统类加载器父类的方法获得的结果是扩展类加载器

3、当前线程上下文的ClassLoader就是系统类加载器
Thread.currentThread().setContextClassLoader(this.loader)就是将系统类加载器设置为当前线程的上下文加载器,所以Thread.currentThread().getContextClassLoader()获取到的就是系统类加载器

02-复习:类的加载器分类

在这里插入图片描述
在这里插入图片描述
父类加载器和子类加载器的关系:

在这里插入图片描述
正是由于子类加载器中包含着父类加载器的引用,所以可以通过子类加载器的方法获取对应的父类加载器

注意:
启动类加载器通过C/C++语言编写,而自定义类加载器都是由Java语言编写的,虽然扩展类加载器和应用程序类加载器是被jdk开发人员使用java语言来编写的,但是也是由java语言编写的,所以也被称为自定义类加载器

1-引导类加载器

在这里插入图片描述

在这里插入图片描述
引导类加载器需要加载的jar包文件:
在这里插入图片描述
执行结果:
在这里插入图片描述
2-扩展类加载器
在这里插入图片描述
无法通过扩展类加载器获得引导类加载器,因为引导类加载器是用C/C++语言编写的,所以获取的值是null

2-扩展类加载器:

在这里插入图片描述
在这里插入图片描述

3-系统类加载器

在这里插入图片描述

4-用户自定义类加载器

在这里插入图片描述

03-测试不同的类的加载器

在这里插入图片描述

在这里插入图片描述
获取当前线程上下文的ClassLoader的结果就是系统类加载器,这个可以在Launcher.java中被代码证明,即:this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);Thread.currentThread().setContextClassLoader(this.loader);

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

04-ClassLoader源码解析

在这里插入图片描述

ClassLoader的主要方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

loadClass()剖析

loadClass()方法是ClassLoader.java类中的主要方法。
在这里插入图片描述
在这里插入图片描述
分析:
假设现在需要加载User类,我们自然也知道这需要使用系统类加载器加载,接下来来到系统类加载器的loadClass()方法中,假设系统类加载器没有加载User类,同步代码块的作用在上面注释中写的很清楚,然后直接获取User类的Class对象,如果c为null,将会判断系统类加载器的父类加载器是否为空,我们知道系统类加载器的父类加载器是扩展类加载器(在Launcher.java类中验证),那么parent不为null,之后进入if判断,将会调用扩展类加载器的loadClass()方法,此方法和上面的loadClasss()方法是一样的,接下来来到扩展类加载器的loadClass()方法中的判断就不在说了,因此扩展类加载器没有加载User类,所以c是null,然后parent是null(在Launcher.java中验证,通过扩展类加载器获取到的父类加载器就是null),将会执行c=findBootstrapClassOrNull(Name),这个就是判断引导类加载器是否加载了User类,如果没有加载该类就会尝试加载User类,也就是如下代码:

private Class<?> findBootstrapClassOrNull(String name)
{
    if (!checkName(name)) return null;

    return findBootstrapClass(name);
}

其中checkName()方法不用管,在本例中那个不会执行,然后会执行findBottstrapClass()fhfa ,如果加载成功返回对应的Class实例,否则返回null,由于引导类加载器不会加载User类,所以本次结果肯定是null了,那回到扩展类加载器的loadClass()方法中,继续看c = findBootstrapClassOrNull(name),那c就是null了,之后便会调用c = findClass(name);,这个将会调用URLClassLoader类中的重写findClass方法,这个方法就不带大家看了,不过该方法会返回一个null值,毕竟User类不是被扩展类加载器加载的,接下来回到系统类加载器的loadClass()方法中,继续看c = parent.loadClass(name, false),由于返回值c是null,然后便会调用c = findClass(name),系统类加载器正好可以加载User类,返回一个Class对象

SecureClassLoader与URLClassLoader

在这里插入图片描述
在这里插入图片描述

ExtClassLoader与AppClassLoader

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Class.forName()与ClassLoader.loadClass()

在这里插入图片描述

05-双亲委派模型

定义与本质

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

优势与劣势

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

破坏双亲委派机制
破坏双亲委派机制1

在这里插入图片描述
以上简单来说就是jdk1.2之前还没有引入双亲委派机制,所以jdk1.2之前就是破坏双亲委派机制的情况

破坏双亲委派机制2

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
简单来说就是线程上下文类加载器让启动类加载器和系统类加载器直接联系起来了,中间的扩展类加载器被省略了,所以这破坏了双亲委派机制,其中线程上下文类加载器就是系统类加载器,这个证明在01-概述—>载器之间的关系中有解释

破坏双亲委派机制3

在这里插入图片描述
在这里插入图片描述

热替换的实现

在这里插入图片描述

在这里插入图片描述
每次调用方法之前都要加载字节码文件,然后创建对象,我们可以把字节码文件变成最新的,那么创建的对象肯定是最新的,所以这就完成了热替换

06-沙箱安全机制

在这里插入图片描述

JDK1.0时期

在这里插入图片描述

JDK1.1时期

在这里插入图片描述

JDK1.2时期

在这里插入图片描述
在这里插入图片描述

JDK1.6时期

在这里插入图片描述

07-自定义类的加载器

在这里插入图片描述
在这里插入图片描述

实现方式

在这里插入图片描述
在这里插入图片描述

08-Java9新特性

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码: 
public class ClassLoaderTest {
    public static void main(String[] args) {
        System.out.println(ClassLoaderTest.class.getClassLoader());
        System.out.println(ClassLoaderTest.class.getClassLoader().getParent());
        System.out.println(ClassLoaderTest.class.getClassLoader().getParent().getParent());
 
        //获取系统类加载器
        System.out.println(ClassLoader.getSystemClassLoader());
        //获取平台类加载器
        System.out.println(ClassLoader.getPlatformClassLoader());
        //获取类的加载器的名称
        System.out.println(ClassLoaderTest.class.getClassLoader().getName());
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值