代码块的使用细节
介绍代码块的基本使用,对类的加载时机,及子类对象实例化过程中,静态/普通属性初始化、静态/普通代码块、构造方法的执行顺序的分析。
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();
}
}
注意:在创建子类实例对象时,会先调用父类的构造方法,初始化父类空间。