静态代码块,构造代码块,构造函数及其执行顺序和逻辑
静态代码块:
- 随着类的加载而执行,只执行一次,并优先于主函数。具体说,静态代码块是由类调用的。类调用时,先执行静态代码块,然后才执行主函数的。
- 静态代码块其实就是给类初始化的,而构造代码块是给对象初始化的。
- 静态代码块中的变量是局部变量,与普通函数中的局部变量性质没有区别。
- 一个类中可以有多个静态代码块(顺序由上至下)。
构造代码块
- 构造代码块的作用是给对象进行初始化。
- 对象一建立就运行构造代码块了,而且优先于构造函数执行。这里要强调一下,有对象建立,才会运行构造代码块,类不能调用构造代码块的,而且构造代码块与构造函数的执行顺序是前者先于后者执行。
- 构造代码块与构造函数的区别是:构造代码块是给所有对象进行统一初始化,而构造函数是给对应的对象初始化,因为构造函数是可以多个的,运行哪个构造函数就会建立什么样的对象,但无论建立哪个对象,都会先执行相同的构造代码块。也就是说,构造代码块中定义的是不同对象共性的初始化内容。
构造函数
- 对象一建立,就会调用与之相应的构造函数,也就是说,不建立对象,构造函数是不会运行的。
- 构造函数的作用是用于给对象进行初始化。
- 一个对象建立,构造函数只运行一次,而一般方法可以被该对象调用多次。
Java类初始化顺序
- 单一类:静态变量,静态代码块 > 变量,构造代码块 > 构造函数
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
31public class Test06 {
public static String x = "静态变量";
public String y = "变量";
public Test06() {
System.out.println("构造函数");
}
static {
System.out.println(x);
System.out.println("静态代码块");
}
{
System.out.println(y);
System.out.println("构造代码块");
}
public static void main(String[] args) {
/* 输出:静态变量
静态代码块
*/
Test06 test06 = new Test06();
/* 输出:变量
构造代码块
构造函数
*/
}
} - 继承情况:父类静态 > 子类静态 > 父类构造代码块 > 父类构造函数 > 子类构造代码块 > 子类构造函数
静态变量是属于类的,和继承无关!!!
1 | public class Test06 { |
练习
1 | public class StaticTest { |
- 先初始化静态变量,也就是执行new StaticTest(),先执行构造代码块,输出 2
- 再执行构造函数,输出 3 和 a=110,b=0
- 在执行构造函数前,必须初始化实例属性,故 a = 110
- 静态变量从上到下初始化,还没有轮到,因此 b = 0
- 执行静态代码块,输出 1
- 最后进入main函数,执行静态方法staticFunction,输出 4
可以发现:static变量并不一定在实例化变量前被初始化。
父类和子类有同名属性时
public class Test07 {
public static void main(String[] args) {
// 使用多态
Parent chidParent = new Child();
System.out.println("Parent:" + chidParent.getAge()); //40
System.out.println("Parent:" + chidParent.age); //18
System.out.println("Parent:" + chidParent.id); //08
// 直接使用原本类型
Child child = new Child();
System.out.println("Child:" + child.getAge()); //40
System.out.println("Child:" + child.age); //40
System.out.println("Child:" + child.id); //8
}
}
class Child extends Parent {
public Integer age = 40;
public Integer id = 8;
public int getAge() {
return age;
}
}
class Parent {
public Integer age = 18;
public String id = "08";
public int getAge() {
return age;
}
}
对于输出 18 的解释(Java的继承机制):
- 属性属于实例自己的,所以Parent的age属性值是18
- 属性不存在覆盖(即使同名),而方法是实实在在的覆盖(复写)