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

public class Base

{

    private String baseName = "base";

    public Base()

    {

        callName();

    }

 

    public void callName()

    {

        System. out. println(baseName);

    }

 

    static class Sub extends Base

    {

        private String baseName = "sub";

        public void callName()

        {

            System. out. println (baseName) ;

        }

    }

    public static void main(String[] args)

    {

        Base b = new Sub();

    }

}

 
  • null
  • sub
  • base

之前遇到的问题基本上就是类的加载顺序的问题,但是这次,还附带了在初始化时,方法的覆盖问题。

我们知道,类的加载顺序如下:

  1. 父类的静态代码块
  2. 子类的静态代码块
  3. 父类的非静态代码块
  4. 父类构造器
  5. 子类非静态代码块
  6. 子类构造器

父类的静态代码块是先于构造函数加载的,这是我们都清楚的,但是父类的非静态代码块的加载时间,我们需要进行验证一下:

非静态代码块的加载时机

我们利用上述题目中的代码进行验证,如下:

class Base {
    private String baseName = "base";

    public Base() {
        callName();
    }

    public void callName() {
        System.out.println(baseName);
    }

    public static void main(String[] args) {
        Base b = new Base();
    }
}

执行结果为:base

这说明,在进行构造器调用之前,我们已经完成String类型变量baseName的赋值操作;因此,非静态变量的初始化顺序在调用构造器之前。

方法覆盖与多态

下面我们对这个问题,进行验证,执行该问题的代码,我们可以得到输出结果为:null

这是因为当执行父类构造器方法时,进行callName调用,此时的类是一个Sub类型的类,会优先查找Sub类中是否有该方法,如存在该方法,优先进行调用。当调用Sub类中的callName方法时,因为Sub类中baseName尚未初始化,因此打印出的结果为null;

修改程序代码,将Sub类中的callName方法改为callName1,再次运行程序:

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

public class Base

{

    private String baseName = "base";

    public Base()

    {

        callName();

    }

 

    public void callName()

    {

        System. out. println(baseName);

    }

 

    static class Sub extends Base

    {

        private String baseName = "sub";

        public void callName1()

        {

            System. out. println (baseName) ;

        }

    }

    public static void main(String[] args)

    {

        Base b = new Sub();

    }

}

此时的输出结果为:base

因为调用callName方法时,Sub类不存在该方法,因此调用Base类中的callName方法,如上一部分所说,Base类中的非静态变量baseName在调用构造器之前已经完成初始化,所以值为base。

 

 

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值