定义
语法:(修饰符){代码};
其中,
- 修饰符不是必须的,但只能用static修饰
- 使用static修饰的叫静态代码块,没有static修饰的叫普通代码块/非静态代码块(构造代码块)
- 静态代码块和构造代码块都在类中的方法外出现
- ;号可写可不写
代码块的作用
- 构造代码块(普通代码块)在每次调用构造器时都会执行一遍,相当于是对构造器的补充机制,可以做初始化的操作,如果多个构造器中都有重复的语句,可以抽取到初始化块中,提高代码的重用性。
- 静态代码块在类加载时执行,且只被执行一次,常用来执行类属性的初始化,静态块优先于各种代码块以及构造函数。
使用细节
-
static代码块在类加载时执行,只执行一次
-
类在以下这些情况中会被加载:
创建对象时(new)
创建子类对象时,父类会被加载
访问静态成员时 -
普通代码块在创建对象时被调用,每创建一个对象时就调用一次
-
编译器在编译代码时,会将普通属性的初始化内容和构造代码块中的内容拷贝到构造方法第一条语句前,多个构造代码块和普通属性初始化语句会按照定义的先后顺序合并成一份。所以构造器中其实先后隐藏了①super();②普通代码块和普通属性初始化(这是没有显示调用super(参数列表)的情况,如果显示调用了,其实情况也一样)
-
一个对象被创建时,分别执行以下步骤:
加载父类
加载子类
创建子类对象,进入子类构造器 -
综上,一个子类对象创建时,按以下顺序调用(从最上级父类开始):
1、父类的静态代码块的执行和静态变量的初始化(二者优先级一样,按定义的顺序执行)
2、子类(可能有多个,依次往下执行)的静态代码块的执行和静态变量的初始化(二者优先级一样,按定义的顺序执行)
3、父类的构造代码块的执行和普通属性的初始化(二者优先级一样,按定义的顺序执行)
4、父类构造方法中语句的执行
5、子类的构造代码块的执行和普通属性的初始化(二者优先级一样,按定义的顺序执行)
6、子类构造方法中语句的执行
个人理解:(其实3、4合起来就是super()也即父类构造函数的调用;5、6合起来就是子类构造函数的调用,多继承时,先从顶级父类开始执行构造函数,执行完了以后,依次往下执行子类的构造函数)
代码示例:
package com.dhw.codeblock;
public class CodeBlock {
public static void main(String[] args) {
new B();
}
}
class A { //父类
private static int n1 = getVal01();
static {
System.out.println("A 的一个静态代码块..");//(2)
}
{
System.out.println("A 的第一个普通代码块..");//(5)
}
public int n3 = getVal02();//普通属性的初始化
public static int getVal01() {
System.out.println("getVal01");//(1)
return 10;
}
public int getVal02() {
System.out.println("getVal02");//(6)
return 10;
}
public A() {
//super()
//构造代码块和普通属性的初始化
System.out.println("A 的构造器");//(7)
}
}
class B extends A {
private static int n3 = getVal03();
static {
System.out.println("B的一个静态代码块..");//(4)
}
public int n5 = getVal04();
{
System.out.println("B 的第一个普通代码块..");//(9)
}
public static int getVal03() {
System.out.println("getVal03");//(3)
return 10;
}
public int getVal04() {
System.out.println("getVal04");//(8)
return 10;
}
public B() {
//super()
//普通代码块和普通属性的初始化
System.out.println("B的构造器");//(10)
}
}