0%

静态代码块与构造函数

概念

静态代码块:用static{}包围的代码

构造代码块:用{}包围的代码

构造函数:类中与类同名的无返回值函数

特性

构造函数

构造函数是类中与类同名的无返回值函数

1
2
3
4
5
6
//A.java
public class A{
public A(){
// 构造函数
}
}
  1. 在创建类的对象时就会调用其构造函数
  2. 构造函数的作用就是为对象进行初始化
  3. 构造函数可以重载,但要保证所有构造函数都有唯一的参数列表
  4. 当类中没有构造函数,jvm会创建一个无参的默认构造函数
  5. 当创建子类的对象时,其父类中一定要有无参的构造函数

构造代码块

1
2
3
4
5
public class A{
{
//构造代码块
}
}
  1. 构造代码块也可用于对象的初始化,且先于构造函数执行
  2. 只用在创建类的对象时才会调用构造代码块
  3. 一个类中可以有多个构造代码块,且执行顺序按先后位置先后执行

静态代码块

1
2
3
4
5
public class A{
static{
// 静态代码块
}
}
  1. 静态代码块在类被jvm加载时执行,且只执行一次
  2. 静态代码块中的变量都是局部变量
  3. 静态代码块中不可使用非static的变量
  4. 一个类中可以有多个静态代码块

三者的执行顺序

静态代码块>代码块>构造函数

验证

单类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class C {
static {
System.out.println("I am C class static code block");// 静态代码块
}

public C(){
System.out.println("I am C class constructor");// 构造函数
}

{
System.out.println("I am C class code block two");// 构造代码块
}

{
System.out.println("I am C class code block one");// 构造代码块
}

public static void main(String[] args){
C c = new C();
}
}

执行结果

1
2
3
4
I am C class static code block
I am C class code block two
I am C class code block one
I am C class constructor

在main函数中添加C c2 = new C();后再次执行,
执行结果

1
2
3
4
5
6
7
I am C class static code block//静态代码块只执行一次
I am C class code block two
I am C class code block one
I am C class constructor
I am C class code block two
I am C class code block one
I am C class constructor

继承的情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class A{
static {
System.out.println("I am A class static code block");
}

public A(){
System.out.println("I am A class constructor");
}

{
System.out.println("I am A class code block");
}
}
public class B extends A {
static {
System.out.println("I am B class static code block");
}

public B(){
System.out.println("I am B class constructor");
}

{
System.out.println("I am B class code block");
}

public static void init(){
System.out.println("I am B class static method");
}

public static void main(String[] args){
B b = new B();
}

执行结果

1
2
3
4
5
6
I am A class static code block
I am B class static code block
I am A class code block
I am A class constructor
I am B class code block
I am B class constructor

由于B类继承A类,由继承特性可以了解到,当调用B类的构造函数时,会隐式的调用A类中的无参构造函数,如果A类仍是某个类的子类,程序会继续向上寻找A类的父类的无参构造函数。
而static代码块的执行方式与之类似,当jvm加载B类时,发现B类继承自A类,因此会优先去执行A类中的静态代码块,然后执行B类的静态代码块,之后依次调用构造代码块和构造函数。

这里还存在一个问题,那就是main方法的执行时间
如果将main方法中的代码改为

1
2
3
System.out.println("I am B class main method");
B b = new B();
B.init();

执行的结果是:

1
2
3
4
5
6
7
8
I am A class static code block
I am B class static code block
I am B class main method
I am A class code block
I am A class constructor
I am B class code block
I am B class constructor
I am B class static method

这里可以看到既执行了A类的静态代码块,也执行了B类的静态代码块,之后执行B类中的静态方法。在程序运行时,执行B.main();jvm会去加载B类,当发现B类继承自A类时,会继续加载A类,当所需类都加载完成后,在执行B.init方法。

因此构造代码块,静态代码块,main方法,构造函数的执行顺序为
静态代码块>main方法>构造代码块>构造函数