Java学习笔记-初始化

时间:2022-01-19 11:49:58

静态数据的初始化

静态数据初始化的几个原则:

  • 次数】无论创建多少个对象,静态数据只初始化一次
  • 【时机】静态初始化只有在必要时刻才会进行。只有在第一次访问静态数据或静态域时,才会初始化
  • 【与是否创建对象无关】当加载类时,就会初始化静态对象,无论是否创建该类对象
  • 【顺序】当静态与非静态对象共存时,先初始化静态对象

值得注意的是,非静态对象也会在构造函数之前初始化

举例代码如下

//: initialization/StaticInitialization.java
// Specifying initial values in a class definition.
import static net.mindview.util.Print.*;

class Bowl {
Bowl(int marker) {
print("Bowl(" + marker + ")");
}
void f1(int marker) {
print("f1(" + marker + ")");
}
}

class Table {
static Bowl bowl1 = new Bowl(1);
Table() {
print("Table()");
bowl2.f1(1);
}
void f2(int marker) {
print("f2(" + marker + ")");
}
static Bowl bowl2 = new Bowl(2);
}

class Cupboard {
Bowl bowl3 = new Bowl(3);
static Bowl bowl4 = new Bowl(4);
Cupboard() {
print("Cupboard()");
bowl4.f1(2);
}
void f3(int marker) {
print("f3(" + marker + ")");
}
static Bowl bowl5 = new Bowl(5);
}

public class StaticInitialization {
//加载StaticInitialization类时,即开始初始化static对象,也就是table和cupboard
public static void main(String[] args) {
print("Creating new Cupboard() in main");

// 再次生成Cupboard对象,但是此时静态对象已经加载过一遍
// 所以只会在调用构造函数前生成bowl3
new Cupboard();
print("Creating new Cupboard() in main");
new Cupboard();
table.f2(1);
cupboard.f3(1);
}

// 初始化table对象,加载Table类
// 由于是第一次加载Table类,所以会初始化Table.bowl1 对象
// 然后初始化下一个static对象,Table.bowl2
// static对象都初始化以后,调用构造函数Table()
static Table table = new Table();

// 由于静态对象先于非静态对象,所以先初始化bowl4,bowl5
// 值得注意的是,非静态对象也会在构造函数之前初始化(bowl3)
static Cupboard cupboard = new Cupboard();
}
/* Output:
Bowl(1)
Bowl(2)
Table()
f1(1)
Bowl(4)
Bowl(5)
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
f2(1)
f3(1)
*/
//:~

继承与初始化

与C艹不同,java中所有事物都是对象。也就是说,每个类的编译代码都在自己独立文件中,只有在需要使用程序时才会加载,而不是像C++这样按顺序加载的。

当程序中有继承存在时,会按照继承关系依次加载所有相关的类。自然的,也会初始化各父类中的静态变量。当父类中的静态变量初始化完毕以后,子类中的静态变量才会开始加载。(但在生成对象之前,不会初始化非静态变量)

一般来说,初始化的顺序是:

父类静态变量初始化 -> 子类静态变量初始化
-> 父类非静态变量初始化 -> 父类构造函数
-> 子类非静态变量初始化 -> 子类构造函数

前两个环节无论生不生成对象,都会执行。
后四个环节只有在生成对象时才会执行

//: reusing/Beetle.java
// The full process of initialization.
import static net.mindview.util.Print.*;

class Insect {
private int i = printInit("i is initialized");
protected int j;
Insect() {
print("i = " + i + ", j = " + j);
j = 39;
}
private static int x1 =
printInit("static Insect.x1 initialized");
static int printInit(String s) {
print(s);
return 47;
}
}

public class Beetle extends Insect {
// 找到Beetle类的编译代码以后,发现有一个基类,所以需要先加载基类
// 首先初始化Insect中的 x1,然后初始化Beetle.x2 (只初始化静态变量)
// 此时必要的类已加载完毕,可以执行main函数
private int k = printInit("Beetle.k initialized");
public Beetle() {
print("k = " + k);
print("j = " + j);
}
private static int x2 =
printInit("static Beetle.x2 initialized");
public static void main(String[] args) {
print("Beetle constructor");

// 开始创建beetle对象
// 但是由于beetle继承自insect类,所以要先对insect类进行初始化
// 对于任何一个类,生成对象的顺序都是 静态变量初始化->非静态变量初始化->构造函数
Beetle b = new Beetle();
}
}
/* Output:
static Insect.x1 initialized
static Beetle.x2 initialized
Beetle constructor
i = 9, j = 0
Beetle.k initialized
k = 47
j = 39
*/
//:~