JAVA中子类和父类各种属性和代码块的加载顺序

这是面试或笔试中经常出现的一个问题:就是当子类继承父类之后,初始化子类,那么子类和父类各部分的加载顺序是怎样的?

答案是,顺序如下:

1. 父类的静态代码块 & 静态属性。(存在多个静态代码块 / 静态属性的话按照编写顺序由上至下依次执行)

2. 子类的静态代码块 & 静态属性。(存在多个静态代码块 / 静态属性的话按照编写顺序由上至下依次执行)

3. 父类的非静态代码块 & 非静态属性。(存在多个非静态代码块 / 非静态属性的话按照编写顺序由上至下依次执行)

4. 父类的构造函数。

5. 子类的非静态代码块 & 非静态属性。(存在多个非静态代码块 / 非静态属性的话按照编写顺序由上至下依次执行)

6. 子类的构造函数。

一共6项,看起来好像很多,但是其实都是遵循这么一条规则而已:

静态早于非静态的同时父类早于子类。

正是因为静态早于非静态。所以我们在写程序时,静态不能调用非静态,因为静态加载完成后,并不能保证非静态此时也加载完成了。但是非静态可以调用静态,因为你调用了非静态的时候非静态肯定先加载完成之后才能执行,而静态会早于非静态加载完成,此时静态也一定加载完成了。

而父类早于子类也很好理解,道理如同你不可能比你爹先出生,因为子类的很多行为和属性都要从父类身上获取下来才行。


那么我们通过代码来证实以上结论,为了验证,我们特地让静态及非静态的代码块和属性交叉排列

父类,SuperClass:

public class SuperClass {

    public String property1 = initProperty(1);
    public static String staticProperty1 = initStaticProperty(1);

    {
        System.out.println("这是父类的非静态代码块1");
    }

    static {
        System.out.println("这是父类的静态代码块1");
    }

    {
        System.out.println("这是父类的非静态代码块2");
    }

    static {
        System.out.println("这是父类的静态代码块2");
    }

    {
        System.out.println("这是父类的非静态代码块3");
    }

    static {
        System.out.println("这是父类的静态代码块3");
    }

    SuperClass() {
        System.out.println("这是父类的构造函数");
    }
    public String property2 = initProperty(2);
    public static String staticProperty2 = initStaticProperty(2);
    public String property3 = initProperty(3);
    public static String staticProperty3 = initStaticProperty(3);

    public String initProperty(int order) {
        System.out.println("这是父类的非静态属性" + order);
        return "这是父类的非静态属性" + order;
    }

    public static String initStaticProperty(int order) {
        System.out.println("这是父类的静态属性" + order);
        return "这是父类的静态属性" + order;
    }

}

子类,SubClass:

public class SubClass extends SuperClass{


    {
        System.out.println("这是子类的非静态代码块1");
    }

    static {
        System.out.println("这是子类的静态代码块1");
    }

    {
        System.out.println("这是子类的非静态代码块2");
    }

    static {
        System.out.println("这是子类的静态代码块2");
    }

    {
        System.out.println("这是子类的非静态代码块3");
    }

    static {
        System.out.println("这是子类的静态代码块3");
    }

    public String property1 = initProperty(1);
    public static String staticProperty1 = initStaticProperty(1);
    public String property2 = initProperty(2);
    public static String staticProperty2 = initStaticProperty(2);
    public String property3 = initProperty(3);
    public static String staticProperty3 = initStaticProperty(3);

    public String initProperty(int order) {
        System.out.println("这是子类的非静态属性" + order);
        return "这是子类的非静态属性" + order;
    }

    public static String initStaticProperty(int order) {
        System.out.println("这是子类的静态属性" + order);
        return "这是子类的静态属性" + order;
    }

    SubClass() {
        System.out.println("这是子类的构造函数");
    }

}

随后我们初始化子类:

public static void main(String[] args) {
    SubClass subClass = new SubClass();
}

可以看到控制台输出顺序如下:

通过观察下面几行打印以及代码可知:

(非)静态属性与(非)静态代码块的加载优先级一样高, 加载顺序取决于谁写在前面。

但是我们会通过下图发现一个问题:

哎,这里不是应该输出父类的非静态属性1,2,3吗,为什么是子类的?那是因为,父类和子类的非静态属性的初始化方法名都是 initProperty(),所以,子类是重写了父类的方法。这点一定要注意哦。

那么,接下来,我们修改子类的非静态属性的初始化方法名,以此来避免重写造成的多态现象,使我们更加直观的看到父类和子类的加载顺序:

子类代码修改后如下(就是将initProperty方法更名为subInitProperty):

package initorderstudy;

public class SubClass extends SuperClass{


    {
        System.out.println("这是子类的非静态代码块1");
    }

    static {
        System.out.println("这是子类的静态代码块1");
    }

    {
        System.out.println("这是子类的非静态代码块2");
    }

    static {
        System.out.println("这是子类的静态代码块2");
    }

    {
        System.out.println("这是子类的非静态代码块3");
    }

    static {
        System.out.println("这是子类的静态代码块3");
    }

    public String property1 = subInitProperty(1);
    public static String staticProperty1 = initStaticProperty(1);
    public String property2 = subInitProperty(2);
    public static String staticProperty2 = initStaticProperty(2);
    public String property3 = subInitProperty(3);
    public static String staticProperty3 = initStaticProperty(3);

    // 将重写方法更名,以便不重写父类重名方法
    public String subInitProperty(int order) {
        System.out.println("这是子类的非静态属性" + order);
        return "这是子类的非静态属性" + order;
    }

    public static String initStaticProperty(int order) {
        System.out.println("这是子类的静态属性" + order);
        return "这是子类的静态属性" + order;
    }

    SubClass() {
        System.out.println("这是子类的构造函数");
    }

}

执行main方法后结果如图:

由此,子类和父类个属性和代码块的加载顺序如上所述:静态早于非静态的同时父类早于子类。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值