代码案例摘自:https://blog.csdn.net/a647777/article/details/108789049
概念摘自百度百科
初始化块概念
初始化块用于初始化类的对象。分为实例初始化块和静态初始化块。其中在一个对象编译的过程中,静态初始化块只在类加载的时候被初始化一次,并且是初始化内容存在堆的方法区(元空间)中,而实例化代码块,则是在对象被实例化的时候调用。
初始化块是类的第4种成员(成员变量、方法、构造器),与构造器作用有些类似,用于对JAVA对象进行初始化操作。
初始化块定义
实例化代码块:
{ Java语句; }
使用static关键字来定义“静态代码块”
static{ Java语句; }
初始化块举例
例如:
public class Animal { //定义初始化块 { int a = 6; if(a>4) { System.out.println("Animal初始化块,局部变量a的值大于4"); } System.out.println("Animla的初始化块"); } //再定义一个初始化块 { System.out.println("Animal的第二个初始化块"); } //定义构造器 public Animal() { System.out.println("Animal的无参构造器"); } } public class Demo01 { public static void main(String[] args) { Animal a = new Animal(); } }
运行结果如下:
可见,JAVA创建对象时,首先执行初始化块。
如果一个类中定义了多个初始化块,则按照顺序执行(这其实没有什么意义,因为初始化块都可以合并为一个)。并且,初始化块在构造器(构造函数)之前执行。
初始化块与构造器区别
二者的区别是:
- 初始化块是一段固定的代码,它无法接受任何参数,对一个类的所有对象进行的初始化处理完全相同;
- 而构造器则是可以带参数的,对不同的对象,参数不同,可以进行不同的初始化处理。
静态初始化块
与静态方法、静态成员变量类似,在初始化块之前加上static就变成了静态初始化块。
普通初始化块是对象的,负责初始化具体对象;
静态初始化块是类的,负责初始化类。
与静态方法相同,静态初始化块不能访问非静态方法,非静态成员变量(因为静态初始化块是在类加载的时候就执行了的,这个时候可能还没有类的对象,就没办法执行非静态方法、非静态成员变量)
初始化块执行顺序
JAVA中,创建一个对象时,若是第一次创建该类的对象,则会首先加载并初始化该类,因此会首先执行其所有父类的静态初始化块(按照顺序执行,首先是最顶层父类,然后是下一层,层层向下执行),最后是其本身的静态初始化块。
再依次执行所有父类的初始化块、构造器,最后是自己类的初始化块、构造器。
一旦该对象创建成功,该类在虚拟机中将一直存在,第二次创建该类的对象时,就无需加载与初始化类。
其中,类的静态初始化块、静态成员变量的声明都可以看作是类的初始化代码,执行顺序依代码顺序而定。
代码举例如下:
class Person { static { System.out.println("我是Person类的静态初始化块"); } { System.out.println("我是Person类的普通初始化块"); } public Person() { System.out.println("我是Person类的无参构造器"); } } class Police extends Person{ static { System.out.println("我是Police类的静态初始化块"); } { System.out.println("我是Police类的普通初始化块"); } public Police() { System.out.println("我是Police类的无参构造器"); } public Police(int a) { //调用自己的无参构造器 this(); System.out.println("我是Police类的有参构造器,参数为:"+a); } } class SWAT extends Police{ static { System.out.println("我是SWAT的静态初始化块"); } { System.out.println("我是SWAT的普通初始化块"); } public SWAT() { //调用直接父类的有参构造器 super(10); System.out.println("我是SWAT的无参构造器"); } } public class Demo01 { public static void main(String[] args) { new SWAT(); } }
上述代码创建了三个类,Person,Police,SWAT。其中,Person是Police的直接父类,Police是SWAT的直接父类。
输出结果为:
我是Person类的静态初始化块 我是Police类的静态初始化块 我是SWAT的静态初始化块 我是Person类的普通初始化块 我是Person类的无参构造器 我是Police类的普通初始化块 我是Police类的无参构造器 我是Police类的有参构造器,参数为:10 我是SWAT的普通初始化块 我是SWAT的无参构造器
因为这是第一次使用SWAT这个类,因此需要初始化类,因此会首先依次执行Person类的静态初始化块、Police类的静态初始化块和SWAT类的静态初始化块。
随后,创建对象时,则会依次执行各个父类的初始化块,构造器。首先是Person类的普通初始化块、无参构造器,然后是Police类的普通初始化块、无参构造器、有参构造器(因为SWAT的无参构造器中调用了Police的有参构造器(super(10)),而Police的有参构造器中调用了Police的无参构造器(this())),最后是SWAT自己的普通初始化块、无参构造器。
修改一下代码
public class Demo01 { public static void main(String[] args) { new SWAT(); new SWAT(); } }
输出将增加:
我是Person类的普通初始化块 我是Person类的无参构造器 我是Police类的普通初始化块 我是Police类的无参构造器 我是Police类的有参构造器,参数为:10 我是SWAT的普通初始化块 我是SWAT的无参构造器
因为该类已经被加载过了,因此,各个类的静态初始化块均不会被重新运行。