Java类加载及实例化的调用顺序

Posted Kingsley

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java类加载及实例化的调用顺序相关的知识,希望对你有一定的参考价值。

标题起得略拗口,大概意思就是说在一个Java类中,域和构造方法的调用顺序。

1. 没有继承的情况

单独一个类的场景下,初始化顺序为依次为 静态数据,继承的基类的构造函数,成员变量,被调用的构造函数。

其中静态数据只会初始化一次。

package com.khlin.binding.test;

public class App2 {
    public static void main(String[] args) {
        Son son = new Son();
    }
}

class Son {

    public Son() {
        System.out.println("this is son.");
    }

    public Son(int age) {
        System.out.println("son is " + age + " years old.");
    }
    
    private Height height = new Height(1.8f);
    
    public static Gender gender = new Gender(true);
}

class Height {
    public Height(float height) {
        System.out.println("initializing height " + height + " meters.");
    }
}

class Gender {
    public Gender(boolean isMale) {
        if (isMale) {
            System.out.println("this is a male.");
        } else {
            System.out.println("this is a female.");
        }
    }
}

输出:

 

2. 继承的情况

稍微修改一下代码,添加两个基类,让Son继承Father, Father继承Grandpa。

继承的情况就比较复杂了。由于继承了基类,还将往上回溯,递归地调用基类的无参构造方法。

在我们的例子中,在初始化静态数据后,会先往上追溯,调用Father的默认构造方法,此时再往上追溯到Grandpa的默认构造方法。

注:如果在子类的构造方法中,显式地调用了父类的带参构造方法,那么JVM将调用指定的构造方法而非默认构造方法。

基类和子类均有静态数据,成员变量和构造方法的场景

我们继续修改代码,让其最终呈现如下:

 1 package com.khlin.binding.test;
 2 
 3 public class App2 {
 4     public static void main(String[] args) {
 5         Son son = new Son();
 6     }
 7 }
 8 
 9 class Grandpa {
10     public Grandpa() {
11         System.out.println("this is grandpa.");
12     }
13 
14     public Grandpa(int age) {
15         System.out.println("grandpa is " + age + " years old.");
16     }
17 
18     private Height height = new Height(1.5f);
19 
20     public static Gender gender = new Gender(true, "grandpa");
21 }
22 
23 class Father extends Grandpa {
24 
25     public Father() {
26         System.out.println("this is father.");
27     }
28 
29     public Father(int age) {
30         System.out.println("father is " + age + " years old.");
31     }
32 
33     private Height height = new Height(1.6f);
34 
35     public static Gender gender = new Gender(true, "father");
36 }
37 
38 class Son extends Father {
39 
40     public Son() {
41         super(50);
42         System.out.println("this is son.");
43     }
44 
45     public Son(int age) {
46         System.out.println("son is " + age + " years old.");
47     }
48 
49     private Height height = new Height(1.8f);
50 
51     public static Gender gender = new Gender(true, "son");
52 }
53 
54 class Height {
55     public Height(float height) {
56         System.out.println("initializing height " + height + " meters.");
57     }
58 }
59 
60 class Gender {
61     public Gender(boolean isMale) {
62         if (isMale) {
63             System.out.println("this is a male.");
64         } else {
65             System.out.println("this is a female.");
66         }
67     }
68 
69     public Gender(boolean isMale, String identify) {
70         if (isMale) {
71             System.out.println(identify + " is a male.");
72         } else {
73             System.out.println(identify + " is a female.");
74         }
75     }
76 }

最后输出会是什么呢?

参考下面另一个案例的分析。链接:http://bbs.csdn.net/topics/310164953 

在我们的示例中,加载顺序应该是这样的:

Grandpa 静态数据

Father 静态数据

Son 静态数据

Grandpa 成员变量

Grandpa 构造方法

Father 成员变量

Father 构造方法

Son 成员变量

Son 构造方法

所以输出如下:

以上是关于Java类加载及实例化的调用顺序的主要内容,如果未能解决你的问题,请参考以下文章

java 中类的加载顺序

java中类的加载情况

java 类属性的加载顺序(带有继承关系的)

多重继承关系初始化顺序及初始化

多重继承关系初始化顺序及初始化

Java对象初始化顺序