代码块的使用细节
介绍代码块的基本使用,对类的加载时机,及子类对象实例化过程中,静态/普通属性初始化、静态/普通代码块、构造方法的执行顺序的分析。
Author: Msuenb
Date: 2023-02-11
代码块基本介绍
代码块又称为初始化块,属于类的成员,类似于方法,将逻辑语句封装在方法体中。但和方法不同的是,代码块没有方法名、返回值、参数,只有方法体,而且不通过对象或类显示调用,而是加载类,或创建对象时隐式调用。
基本语法:
【修饰符】 {
    代码...
}
使用说明:
- 
修饰符可选,要写的话,只能是 static
- 
代码块分为两类:静态代码块 (有static修饰)和普通代码块(没static修饰)
- 
逻辑语句可以为输入、输出、方法调用、循环、判断等语句 
示例代码:
public class CodeBlack01 {
    public static void main(String[] args) {
        new Movie("1919");
    }
}
class Movie {
    private String name;
    {
        System.out.println("电影开始...");	// 将相同的语句放到代码块中
    }
    public Movie() {
        // System.out.println("电影开始...");	
        System.out.println("Movie() 被调用...");
    }
    public Movie(String name) {
        this.name = name;
        // System.out.println("电影开始...");
    }
}
注意:代码块的调用优先于构造器
普通代码块可以看作是对构造器的补充机制,如果多个构造器中有重复的语句,可以抽取到代码块中,提高代码的重用性。
代码块使用细节
- 静态代码块的作用是对类进行初始化,它随着类的加载而执行,并且只会执行一次。
- 普通代码块,在创建对象实例时被隐式调用,每创建一个实例对象,就会执行一次。
- 静态代码块只能调用静态成员;普通代码块可以调用任意成员
类的加载时机
- 创建对象实例时(new)
- 创建子类对象实例,父类也会被加载
- 使用类的静态成员时(静态属性, 静态方法)
注意:使用静态成员常量时,类不会被加载!!!
示例代码:
public class CodeBlockDetail01 {
    public static void main(String[] args) {
        // 1. 创建对象实例时 该类被加载
        // new AA();
        // new AA();   // 静态代码块只会执行一次 普通代码块会再次执行
        // 2. 创建子类对象时 父类也被加载(父类先 子类后)
        // new BB();
        // 3. 调用静态成员时 该类被加载
        System.out.println(AA.n1);   // 普通代码块不会执行
    }
}
class AA {
    public static int n1 = 996;
    {
        System.out.println("AA 的普通代码块...");
    }
    static {
        System.out.println("AA 的静态代码块...");
    }
}
class BB extends AA {
    static {
        System.out.println("BB 的静态代码块...");
    }
}
子类对象实例化过程
在创建一个子类对象时,它们的静态代码块、静态属性初始化、普通代码块、普通属性初始化、构造方法的调用顺序如下:
- 父类的静态代码块和父类的静态属性初始化(优先级一样,按定义的顺序执行)
- 子类的静态代码块和子类的静态属性初始化(优先级一样,按定义的顺序执行)
- 父类的普通代码块和父类的普通属性初始化(优先级一样,按定义的顺序执行)
- 父类的构造方法
- 子类的普通代码块和子类的普通属性初始化(优先级一样,按定义的顺序执行)
- 子类的构造方法
示例代码:
class Father {
    private int a = getValA();         	// 5
    private static int b = getValB();  	// 1
    {                               	// 6
        System.out.println("父类普通代码块");
    }
    
    static {                        	// 2
        System.out.println("父类静态代码块");
    }
    public Father() {               	// 7
        System.out.println("父类构造器");
    }
    public int getValA() {
        System.out.println("父类普通属性初始化");
        return 1;
    }
    public static int getValB() {
        System.out.println("父类静态属性初始化");
        return 2;
    }
}
class Son extends Father {
    private int c = getValC();         	// 8
    private static int d = getValD();  	// 3
    {                               	// 9
        System.out.println("子类普通代码块");
    }
    static {                        	// 4
        System.out.println("子类静态代码块");
    }
    public Son() {                  	// 10
        // 隐含 super();
        System.out.println("子类构造器");
    }
    public int getValC() {
        System.out.println("子类普通属性初始化");
        return 1;
    }
    public static int getValD() {
        System.out.println("子类静态属性初始化");
        return 2;
    }
}
测试类:
public class Test {
    public static void main(String[] args) {
        new Son();
    }
}
注意:在创建子类实例对象时,会先调用父类的构造方法,初始化父类空间。

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号