关于java的一道面试题

时间:2022-04-28 11:28:28

题目如下:

public class Base
{
private String baseName = "base";
public Base()
{
callName();
}
public void callName()
{
System. out. println(this.baseName);
}
static class Sub extends Base
{
private String baseName = "sub";

public void callName()
{
System. out. println (this.baseName) ;
}
}
public static void main(String[] args)
{
Base b = new Sub();
}
}

问:这段代码最终结果会输出什么,为什么?

一开始看到这段代码的时候,并没有放到环境中去编译运行,而是直接是靠着自己的理解去读代码,我自己得出的答案是控制台会输出“sub”,然后,将这段代码在cmd中进行了编译运行之后,命令行中输出的结果却是null,大出意外,一时百思不得其解,遂决定研究一番。看来基础很不牢固啊,哈哈。。。

1、控制台输出的结果:
关于java的一道面试题

2、然后大致分析了一下,之后对代码做了如下修改:

关于java的一道面试题

3、再次编译运行,ok,sub输出了,

关于java的一道面试题

4、此时,试着屏蔽掉Sub子类的构造器中的callName()方法。

关于java的一道面试题

5、再次编译运行,结果同最开始是一模一样。

关于java的一道面试题

6、这个时候,明白了,原来是跟java的类的初始化顺序有关。首先是定义了一个Base父类,并且在Base父类中声明了一个成员变量baseName,和方法callName()以及构造器(默认无参),之后定义了一个静态的Sub子类继承自Base父类。并且重写了父类的callName()方法。然后在main方法里面new了一个Sub对象,因为Sub类继承自Base类,所以在实例化的时候会先去调用Base父类的构造方法,(虽然Sub类中没有定义构造器,但是默认会存在一个无参的构造器),这里不写的话就相当于

public Sub(){
super();//调用父类构造器
}

而父类的构造器中调用了callName()方法,由于子类重写了父类的callName()方法,根据java的多态特性,所以这里实际上调用的是子类Sub类的callName()方法,同时由于这个时候子类的成员变量还没有被初始化,(这个可以去研究一下java类的初始化顺序)所以这个时候Sub类的成员变量basedName=null,即还没有被系统分配内存空间。这就是为什么我们在cmd命令行中看到打印输出的结果是null的原因。

然后,我们再来修改一下代码,将Sub子类的构造器中加入下面这一段代码,注意,super关键字一定是这个构造器方法中最先被执行的代码,所以不能在super关键字之前加代码。(原因:子类继承父类,实例化的时候,先调用父类的构造器,再调用子类的构造器,不然的话违规了)

public Sub(){
super();
System. out. println (this.basedName) ;
}

之后,再编译运行一下,看下结果:

关于java的一道面试题

ok,正常。现在总结一下:
这段代码的初始化顺序,当new一个Sub类的时候,父类的成员变量初始化——》父类的构造器初始化——》子类的成员变量初始化——》子类的构造器初始化。

额,需要说明一点,上面只是自己的一些简单的理解,也不知道正不正确!总而言之,欢迎各位批评指正!!共同学习吧!!