快乐学习 一个网站喵查铺子(catpuzi.com)全搞定~

java的类初始化过程

编程杂谈 尔雅学习君 2023-09-27 扫描二维码
文章目录[隐藏]

类是java知识体系中很重要的基本概念。那么您对类的初始化过程又有多少了解呢?今天,我设计了一段代码,与大家共同探索一个较复杂的类的加载过程。

这段代码涵盖了成员变量(public、protected、private、static)、方法(static)、构造函数、继承的初始化过程。

目录
代码
运行结果

代码

在代码中以注释形式按照java类的初始化过程进行了各步骤的简要说明(Step xx),大家看注释就应该能了解代码的执行逻辑,有些内容进行了展开,写的有些啰嗦了。

需要说明的是,在Father类中有一个静态方法printInit,用于在程序运行时对各成员变量进行赋值,并打印提示信息。一般咱们写程序不会这么干,主要是为了能更好的展示各成员变量的赋值过程。

package com.a321.classloader;
 
 
import java.util.Random;
 
// Step 2: 初始化Father类,由于无父类,则直接初始化Father类的静态成员变量。静态成员变量的初始化顺序依据其在类中的书写顺序。 
class Father {
 
    // Step 3: 初始化rand,此处不好输出,就不输出了。后续有x1代表静态成员变量的执行过程。 
    //         指定随机种子是为了可以形成固定的随机序列,方便复现测试。 
    static Random rand = new Random(37);
 
    // Step 14: 初始化Father的对象,实例化,需要按照书写顺序先初始化成员数据i,默认值为0,然后访问printInit。 
    // Step 16: 为Father.i赋值。 
    public int i = printInit("public Father.i initialized");
    // Step 17: 初始化成员数据j,默认值为0,然后访问printInit。 
    // Step 19: 为Father.j赋值。 
    protected int j = printInit("protected Father.j initialized");
    // Step 20: 初始化成员数据k,默认值为0,此时完成初始化所有的成员数据,开始初始化构造函数。 
    private int k;
 
    // Step 4: 初始化静态成员变量x1,x1的初始值为int的默认值0,此为整个类分配空间时,对所占用的存储空间初始化导致。 
    //         相应的对象引用就初始化为null。所以所有的成员变量都会有默认初始值。。 
    //         由于此处需要调用静态方法printInit进行赋值,所以初始化静态方法printInit。 
    // Step 6: 使用printInit的返回值为x1赋值。所有的静态成员变量已经初始化完成,开始进行子类的初始化。 
    static int x1 = printInit("static Father.x1 initialized");
 
    // Step 21: 初始化构造函数。 
    Father(){
        // Step 22: 输出各成员数据的值,此时可以注意到Father.k依旧为默认值0。 
        System.out.println("Father constructor1: i = " + i + ", j = " + j + ", k = " + k);
        // Step 23: 准备为Father.k赋值,需要先执行printInit。 
        // Step 25: 使用printInit的返回值为k赋值。 
        k = printInit("private Father.k initialized");
        // Step 26: 输出各成员函数的值,此时可以注意到Father.k已经为新值。Father的构造函数执行完成,开始执行初始化子类Child的实例。 
        System.out.println("Father constructor2: i = " + i + ", j = " + j + ", k = " + k);
    }
 
    // Step 5: 初始化静态方法,此处用到了静态成员rand,由于之前已经初始化了,所以可以正常执行,否则会报空指针错误,因为rand的默认初始值为null。为Father.x1执行静态方法,赋值。 
    // Step 9: 为Child.x2执行静态方法,赋值。 
    // Step 15: 为Father.i执行静态方法,赋值。 
    // Step 18: 为Father.j执行静态方法,赋值。 
    // Step 24: 为Father.k执行静态方法,赋值。 
    // Step 28: 为Child.m执行静态方法,赋值。 
    // Step 31: 为Child.n执行静态方法,赋值。 
    static int printInit(String tips){
        int val = rand.nextInt(66);
        System.out.println(tips + ": " + val);
        return val;
    }
}
 
// Step 1: 依据命令行的参数,初始化类Child,发现Child继承于Father,优先加载Father类。由于Java是单根继承,所以可以简单递归的找父类。 
// Step 7: 初始化子类Child,此时父类已经完成初始化,开始子类的静态成员数据的初始化。 
public class Child extends Father{
 
    // Step 27: 初始化子类Child的实例,首先按照书写顺序初始化成员函数。执行printInit方法赋值。 
    // Step 29: 使用printInit的返回值为m赋值。 
    public int m = printInit("public Child.m initialized");
    // Step 30: 初始化成员数据n,执行printInit方法赋值。 
    // Step 32: 使用printInit的返回值为n赋值,此时完成初始化所有的成员数据,开始执行Child的构造函数。 
    private int n = printInit("private Child.n initialized");
 
    // Step 8: 初始化静态成员数据x2,默认值为0,然后初始化静态方法printInit。 
    // Step 10: 使用printInit的返回值为x2赋值,此时完成了子类Child的初始化。 
    static int x2 = printInit("static Child.x2 initialized");
 
    // Step 33: 执行子类Child的构造函数。 
    public Child(){
        // Step 34: 输出各成员函数的值,此时成员函数都已初始化。 
        System.out.println("Child constructor: m = " + m + ", n = " + n);
    }
 
    // Step 11: 开始执行静态成员方法main函数。 
    public static void main(String[] args) {
        // Step 12: 输出main执行的标识。 
        System.out.println("Child.main run");
        // Step 13: 初始化子类Child的对象,发现还有父类Father,所以先初始化Father的对象。 
        // Step 35: 子类Child的初始化过程完成,new的过程完成,赋值给变量c。 
        Child c = new Child();
    }
}

运行结果
程序的执行结果如下

static Father.x1 initialized: 47
static Child.x2 initialized: 15
Child.main run
public Father.i initialized: 30
protected Father.j initialized: 46
Father constructor1: i = 30, j = 46, k = 0
private Father.k initialized: 32
Father constructor2: i = 30, j = 46, k = 32
public Child.m initialized: 6
private Child.n initialized: 8
Child constructor: m = 6, n = 8

喜欢 (0)
关于作者: