论坛首页 入门技术论坛

你或许不知道——在极端情况下,父类访问子类变量所存在的问题

浏览 1254 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2012-05-20   最后修改:2012-05-20
程序清单:
package com.yjk;

public class Parent
{

//定义一个名为i的实例变量
private int i = 1;

public Parent()
{
this.display();
}
public void display()
{
System.out.println(i);
}
}
---------------------------------------------------------------------
public class Son extends Parent
{
//定义一个名为i的实例变量
private int i = 2;

//构造器,将实例变量i初始化为3
public Son()
{
i = 3;                                          //⑵
}
public void display()
{
System.out.println(i);
}

}
---------------------------------------------------------------------
package com.yjk;

public class Test {

public static void main(String[] args)
{
//创建子类实例
new Son();                                    //⑴
}

}
}
---------------------------------------------------------------------

这行代码会调用子类Son里的构造器,由于子类Son继承了父类Parent,而且子类Son的构造器中,并没有显示的使用Super

调用父类Parent的构造器,因此系统会自动调用Parent类中的无参构造器来执行初始化。

在父类Parent的无参构造器中,只是调用了display方法来向控制台输出变量i的值,但是结果却为0。

OK,那么到此,如果你知道是为什么,就可以略过以下内容,反之,请耐心的滚动你的鼠标:

当程序运行至1处时,系统为Son实例对象分配了两块内存空间,是的,换言之就是说,Son对象拥有2个名为i的实例变量

声明:
  永远记住,构造器只负责对 实例对象的变量进行赋值 ,别无它用。构造器不是用来创建对象的,不是,真的不是!

其实在构造器执行之前,系统已经为该对象分派好内存了,此时此刻,内存中的所有变量值都为默认值,比

如:0,false,null.

言归正传,系统为Son对象分配了2块内存,分别用于存放变量i,其中一个属于Parent类定义的i实例变量,另一个属于

Son类定义的i实例变量,此时此刻,二者的值都为0;

接下来,便是先执行父类的构造器对其值进行赋值操作。Parent中定义i的时候便对其进行了初始化操作,且值为1.接着便

执行display()操作,OK,问题来了人,该方法this.diaplay() 中的this 是谁?对,此时还是不够混乱,OK,我们对Parent做

一点小修改:

package com.yjk;

public class Parent
{

//定义一个名为i的实例变量
private int i = 1;

public Parent()
{
System.out.println(this.i);
this.display();

}
public void display()
{
System.out.println(i);
}
}
再次运行,我们可以得到1,0;此刻是不是觉得更加混乱了?

揭秘:

当this在构造器中出现的时候,它所代表的正是当前初始化的实例对象,此时的this位于Son的构造方法中,但是代码们

却出现在父类Parent的构造方法中,那么系统便在Son构造器中,隐式的调用父类Parent构造器中的代码,故,此时的this

是Son对象,既然如此,它输出的却是父类对象的值,这是因为该行代码位于Parent类型中的构造器中,故其编译类型是

Parent,而它实际引用Son了对象.

下面对其进一步进行解释:
package com.yjk;

public class Parent
{

//定义一个名为i的实例变量
private int i = 1;

public Parent()
{
System.out.println(this.i);
this.display();
System.out.println(this.getClass());
}
public void display()
{
System.out.println(i);
}
}

---------------------------------------------------------------------


当变量的编译时的类型和运行时的类型不同时,通过该变量访问它引用的对象的实例变量时,该实例变量的值由声明该

变量的类型决定。但通过该变量调用它引用的对象的实例方法时,该方法行为将由它实际引用的对象来决定。因此,当

程序访问this.i时,将会访问Parent类中定义的i实例变量,也就是输出1;但执行this.display()方法时,则实际表现出Son对

象的行为,也就是输出Son对象的实例变量,即 0.

”—李刚

看一次可能不能完全接受,多看即便就好了,最后,希望这个帖子能够为你带来一定的收获。  
论坛首页 入门技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics