对象初始化过程,两个案例

案例一

带有继承的案例

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public class StaticTest2 {
Person person = new Person("Test");

static {
System.out.println("test static");
}

public StaticTest2() {
System.out.println("test constructor");
}

//main方法
public static void main(String[] args) {
new MyClass();
}
}

class Person {
static {
System.out.println("person static");
}

public Person(String str) {
System.out.println("person " + str);
}
}


class MyClass extends StaticTest2 {
Person person = new Person("MyClass");

static {
System.out.println("myclass static");
}

public MyClass() {
System.out.println("myclass constructor");
}
}

//输出结果
// test static
// myclass static
// person static
// person Test
// test constructor
// person MyClass
// myclass 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
34
35
36
37
38
类初始化(只初始化一次):【静态代码块,静态成员变量赋值】优先级相同,谁在上面先执行时
对象初始化(会初始化多次):【普通代码块,普通成员变量赋值】优先级相同,谁在上面先执行时。然后再执行构造方法,完成对象初始化。
执行对象初始化之前,如果没有进行类初始化,会先进行类初始化。
有父类,先执行自己的类初始化,再执行父类的对象初始化,再执行自己的对象初始化
1. 执行main方法,因为main是静态方法,会先对main方法所在类进行类初始化
System.out.println("test static");

2. 执行main方法中的new MyClass();,会执行MyClass的无参构造,会对MyClass进行类初始化
System.out.println("myclass static");

3. 执行了MyClass类初始化之后,因为有父类,要对父类进行对象初始化,才能对象自己进行对象初始化,
这里父类StaticTest2已经在第 1 步执行过类初始化了,下面进行对象初始化,先给成员变量Person person赋值,
从而执行new Person("Test"),对Person进行对象初始化,先执行类初始化,再执行对象初始化
System.out.println("person static");
System.out.println("person " + str);// Test

4. 父类StaticTest2的成员变量Person person赋值了之后,进行执行构造
System.out.println("test constructor");

5. 执行了父类的对象初始化之后,进行MyClass的对象初始化,1.成员变量赋值,2.执行构造
System.out.println("person " + str);// MyClass
System.out.println("myclass constructor");



下面是简化版:

1. 对main所在的类进行类初始化
System.out.println("test static");
2. 对MyClass进行类初始化
System.out.println("myclass static");
3. 对StaticTest2执行对象初始化
System.out.println("person static");
System.out.println("person " + str);// Test
System.out.println("test constructor");
4. 对MyClass进行对象初始化
System.out.println("person " + str);// MyClass
System.out.println("myclass constructor");

案例二

静态成员变量指向自己,会先把book变量赋值,再进行下面的静态成员变量amount赋值112

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 Book {
public static void main(String[] args) {
staticFunction();
}

static Book book = new Book();

static {
System.out.println("书的静态代码块");
}

{
System.out.println("书的普通代码块");
}

Book() {
System.out.println("书的构造方法");
System.out.println("price=" + price + ",amount=" + amount);
}

public static void staticFunction() {
System.out.println("书的静态方法");
}

int price = 110;
static int amount = 112;
}
//输出结果
// 书的普通代码块
// 书的构造方法
// price=110,amount=0
// 书的静态代码块
// 书的静态方法

注意:上面输出的是amount=0

分析》》》

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1. 执行main方法,因为main是静态方法,会先执行main方法所在类的静态代码块和静态成员变量赋值
静态成员变量的赋值和静态代码块的优先级是相同的,谁在上面先执行
System.out.println("书的普通代码块");

2. 在执行构造代码块之前,先给成员变量赋值,这里不会给静态成员变量赋值,但会给普通成员变量赋值
(这一点是和我之前的理解不一样的,我一直认为静态成员变量的赋值永远比普通成员变量先赋值)
为什么要这样:因为new对象是在堆中的,而静态是在静态区的,所以new的时候不会对静态进行操作,初始化new的那个对象就行了。
因为我们不是调用【对象.静态变量】,而是【类.静态变量】,所以new对象不会进行静态成员变量的初始化
再理解:静态不属于对象,属于类。此时我们正在执行静态static Book book的赋值,而static int amount的静态赋值的执行,要在book赋值之后执行
此时赋值:price=110,但amount仍为0

3. 执行构造代码块
System.out.println("书的构造方法");
System.out.println("price=" + price + ",amount=" + amount);// 110 , 0

4. 给static的Book book赋值之后,执行静态代码块
System.out.println("书的静态代码块");

5. 再执行staticFunction()方法
System.out.println("书的静态方法");