Java类加载机制

1、类加载过程

  • 类加载过程
    多个java文件经过编译打包生成可运行jar包,最终由java命令运行某个主类的main函数启
    动程序,这里首先需要通过类加载器把主类加载到JVM。
    主类在运行过程中如果使用到其它类,会逐步加载这些类。
    注意,jar包里的类不是一次性全部加载的,是使用到时才加载。

类加载到使用整个过程有如下几步:
加载 >> 验证 >> 准备 >> 解析 >> 初始化 >> 使用 >> 卸载

加载:在硬盘上查找并通过IO读入字节码文件,使用到类时才会加载,例如调用
类的main()方法,new对象等等
验证:校验字节码文件的正确性
准备:给类的静态变量分配内存,并赋予默认值
解析:将符号引用替换为直接引用,该阶段会把一些静态方法(符号引用,比如
main()方法)替换为指向数据所存内存的指针或句柄等(直接引用),这是所谓的静态链
接过程(类加载期间完成),动态链接是在程序运行期间完成的将符号引用替换为直接
引用,下节课会讲到动态链接
初始化:对类的静态变量初始化为指定的值,执行静态代码块
在这里插入图片描述

2、 java类初始化顺序

总的一个时序如下
在这里插入图片描述

  • 验证简单场景,没有父类
/**
 * @version 1.0
 * @Description: 测试类加载顺序,没有父类情况
 * @Author: hongjiawei
 * @Date: Created in 2021/3/7
 */
public class SimpleClassLoadTest {
    private static School user = new School();

    static {
        System.err.println("SimpleClassLoadTest的静态代码块");
    }

    {
        System.err.println("code block");
    }

    private Person person = new Person();

    public SimpleClassLoadTest() {
        System.err.println("SimpleClassLoadTest的构造方法");
    }

    public static void main(String[] args) {
        System.err.println("mian函数主入口");
        new SimpleClassLoadTest();
    }
}

class Person {
    public Person() {
        System.err.println("SimpleClassLoadTest的非静态变量");
    }
}

class School {
    public School() {
        System.err.println("SimpleClassLoadTest的静态变量");
    }
}

结果如下

SimpleClassLoadTest的静态变量
SimpleClassLoadTest的静态代码块
mian函数主入口
code block
SimpleClassLoadTest的非静态变量
SimpleClassLoadTest的构造方法
  • 验证复杂场景,存在继承关系
class User {
    public User() {
        System.out.println("作为parent的静态变量,user构造方法");
    }
}

class Parent {
    // 静态变量 
    public static String p_StaticField = "父类--静态变量";

    // 变量
    public String p_Field = "父类--变量";
    protected int j = 0;

    // 静态初始化块 
    static {
        System.out.println(p_StaticField);
        System.out.println("父类--静态初始化块");
    }

    public static User user = new User();

    // 初始化块
    {
        System.out.println(p_Field);
        System.out.println("父类--初始化块");
    }

    // 构造器 
    public Parent() {
        System.out.println("父类--构造器");
        System.out.println("父类 j=" + j);
        j = 20;
    }
}

public class ClassLoadTest extends Parent {
    // 静态变量 
    public static String s_StaticField = "子类--静态变量";
    // 变量 
    public String s_Field = "子类--变量";

    // 静态初始化块 
    static {
        System.out.println(s_StaticField);
        System.out.println("子类--静态初始化块");
    }

    // 初始化块
    {
        System.out.println(s_Field);
        System.out.println("子类--初始化块");
    }

    // 构造器 
    public ClassLoadTest() {
        System.out.println("子类--构造器");
        System.out.println("子类 j=" + j);
    }

    public static void main(String[] args) {
        System.out.println("子类main方法");
        new ClassLoadTest();
    }
}

结果如下

父类--静态变量
父类--静态初始化块
作为parent的静态变量,user构造方法
子类--静态变量
子类--静态初始化块
子类main方法
父类--变量
父类--初始化块
父类--构造器
父类 j=0
子类--变量
子类--初始化块
子类--构造器
子类 j=20
  • 结论
    • 子类的静态变量和静态初始化块的初始化是在父类的变量、初始化块和构造器初始化之前就完成了;
    • 静态变量、静态初始化块顺序取决于它们在类中出现的先后顺序,这个地方挪动下这行代码即可自行验证,public static User user = new User();
    • 变量、初始化块初始化顺序取决于它们在类中出现的先后顺序;
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

矿泉水搬砖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值