关于面向对象的一道基础经典题目(携程2015 Java笔试)

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

为什么?为什么会输出null?

我们先体会一下上边程序的执行流程:

①执行main函数中的:Base b = new Sub();

②进入Sub类的构造函数

③为Sub类的成员变量baseName分配内存,注意此时仅仅是分配内存,所以baseName的值 为Java中定义String类型的成员变量默认值null,(并不是我们所想的“sub”);

④Base构造函数被隐式调用

⑤进入Base类的构造函数

⑥为Base类的成员变量baseName分配内存,注意此时也是仅仅分配内存,这里Base类中的 baseName的值也为 null

⑦执行Base类的初始化语句private String baseName = "base"; //此时Base类中的baseName的值为base;

⑧执行Base类中的构造函数中的具体语句

⑨调用callName()方法,注意:这里的涉及到“多态”的特性(父类可以创建指向子类的对象)。因为子类Sub中重写(Override)了父类中的callName()方法,所以说父类中的callName()方法被隐藏,因此这里的callName()方法其实就是this.callName();

⑩输出Sub类中那个只分配了内存空间而没有赋值的baseName  ----->即 null


这里挖坑就是挖在第③步:我们的错误就在于我们把Java中的声明和初始化看成了一体在C++的世界中,C++并不支持成员变量在声明的时候进行初始化,其需要你在构造函数中显式的初始化其成员变量的值,看起来很土,但其实C++用心良苦。

举个栗子:

public class A {

	private String a = "aaa";
	
//	public A() {
//		super();
//		// TODO Auto-generated constructor stub
//	}

}

①进入A类中的构造器(如果在一个类中没有显式声明构造方法,则默认隐式调用无参的构造方法,即那个注释了的就是被隐式 调用的无参构造方法)。

②声明一个String类型的私有成员变量,名字叫做 a

③初始化 a = "aaa";

④继续执行构造方法剩余的语句,如果没有,则顺序执行类中的语句。










猜你喜欢

转载自blog.csdn.net/tiaopimao3185/article/details/80142564