类加载子系统 -JVM

类加载子系统

结构简图
在这里插入图片描述

一、类加载器的三个阶段

分为

  1. 加载阶段
  2. 链接阶段
  3. 初始化阶段

在这里插入图片描述
主要工作:

  • 从文件当中或者网络当中加载class文件,class文件打开有特殊的文字标识。
  • classLoader只是负责文件的加载,至于是否可以执行成功,就是看ExecutionEngine(执行引擎)决定。
  • 加载的文件保存在方法区,以及一些常量放置在常量池(字符串常量池、byte常量池等)

ClassLoader

class file -> JVM -> 元数据模板
在这里插入图片描述

类加载过程

在这里插入图片描述

链接阶段

  1. 验证阶段在这里插入图片描述
    保证加载文件的正确性 文件格式 元数据验证 字节码验证 符号引用验证
    比如 字节码文件 验证 CA FE BA BE (咖啡北鼻)用来验证
    在这里插入图片描述 2. 准备阶段
    只会赋予初始值,如果是final修饰,就会在编译阶段进行赋值(类变量,就是静态变量,会在这里初始化,但是不会被赋值)
  2. 解析阶段
    本动作是在初始化之后执行
    没有描述

初始化阶段

clinit方法就是初始化静态变量以及静态代码快当中的变量,是jvm自己调用,不需要手动操作,如果没有类变量和静态代码快,就没有clinit方法
在这里插入图片描述

举例:

package com.ll.tree;

public class TestMy {
    static  int i  = 10;
    static{
        i = 100;
        num = 100;//这里可以访问num ,是因为下链接当中的准备阶段就已经初始化完成了,此时由上而下执行会导致num先赋值100,在赋值10,可以赋值,不能调用
    }
    static  int num = 10;
    public static void main(String[] args) {

    }
}


 // access flags 0x8
 static <clinit>()V
   L0
    LINENUMBER 8 L0
    BIPUSH 10
    PUTSTATIC com/ll/tree/TestMy.i : I // i先赋值10 再赋值100
   L1
    LINENUMBER 10 L1
    BIPUSH 100
    PUTSTATIC com/ll/tree/TestMy.i : I
   L2
    LINENUMBER 11 L2
    BIPUSH 100
    PUTSTATIC com/ll/tree/TestMy.num : I // i先赋值100 再赋值10
   L3
    LINENUMBER 13 L3
    BIPUSH 10
    PUTSTATIC com/ll/tree/TestMy.num : I
    RETURN
    MAXSTACK = 1
    MAXLOCALS = 0
}

如果没有静态变量和代码快就没有clinit方法

public class JVMtest1 {
    int i = 1;
    public static void main(String[] args) {
        System.out.println(1);
    }
}

没有clinit方法
在这里插入图片描述

  • init 方法就是构造器
  • clinit方法 是否被同步加锁 如果
    比如说同一个类,在static代码块当中设置一个死循环,使得clinit方法无法执行结束,其他线程就无法创建该对象
package com.company.test.jvm;

/**
 * @author Mr.Lian
 * @create 2021-09-04 14:28
 **/
public class JVMtest1 {
    public static void main(String[] args) {
        ClinitThread c = new ClinitThread();
        ClinitThread c1 = new ClinitThread();
        c.start();
        c1.start();

    }
}

class ClinitStudy{
    static int i = 0;
    static {
        while (i <1) {}
    }
}

class ClinitThread extends Thread{
    @Override
    public void run() {
        System.out.println(this.currentThread().getName()+"进来了");
        ClinitStudy clinitStudy = new ClinitStudy();//创建对象  在执行clinit方法   停在这
        System.out.println(this.currentThread().getName()+"创建完成");
    }
}

类加载器分类

分类
在这里插入图片描述
第一个就是引导类加载器,下面是自定义引导类,凡是继承ClassLoader 就是自定义类加载器
在这里插入图片描述
扩展类加载器
在这里插入图片描述
系统类加载器
在这里插入图片描述

Created with Raphaël 2.3.0 BootStrapClassLoader 引导类加载器, 底层是C,无法获取,java核心类库就是由他加载 扩展类加载器 系统类加载器:加载自定义类 其他类加载器

获取类加载器

在这里插入图片描述

获取上一层加载器

ClassLoader parent = systemClassLoader.getParent();

在这里插入图片描述

为什么要自定义加载类?

加载自定义路径下的class文件

  • 我们需要的类不一定存放在已经设置好的classPath下(有系统类加载器AppClassLoader加载的路径),对于自定义路径中的class类文件的加载,我们需要自己的ClassLoader

进行类的加密和解密操作

  • 有时我们不一定是从类文件中读取类,可能是从网络的输入流中读取类,这就需要做一些加密和解密操作,这就需要自己实现加载类的逻辑,当然其他的特殊处理也同样适用。

实现热部署等

  • 可以定义类的实现机制,实现类的热部署,如OSGi中的bundle模块就是通过实现自己的ClassLoader实现的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值