首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

黑马软件工程师——父类调用子类的成员变量 ?挺有意思

2012-09-05 
黑马程序员——父类调用子类的成员变量 ?挺有意思android培训、java培训、期待与您交流!前两天被问到一个程序,

黑马程序员——父类调用子类的成员变量 ?挺有意思
android培训、java培训、期待与您交流!     



前两天被问到一个程序,觉得挺有意思,拿出来和大家分享一下。程序如下:

class Base
{
    private int i = 2;

    public Base()
    {
        this.display();   
    }

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

class Derived extends Base
{
    private int i = 22;

    public Derived()
    {
        i = 222;                                                             //②
    }

    public void display()
    {
        System.out.println(i);
    }
}
   
public class Test
{
    public static void main(String[] args)
    {
        new Derived();                                                  //①
    }
}

问输出的结果是什么?

     有些java基础好的人可能一下子就能看出来,我java基础不算牢固,查了一些资料明白了里边的缘故,首先告诉大家结果吧,结果是0,为什么呢?我给大家解释一下。

       为了清楚起见我给某些行代码扁了号,首先当程序在①行代码处创建Derived对象时,系统开始为这个Derived对象分配内存空间,需要指出的是,这个Derived对象并不是只有一个i实例变量,它将拥有两个i实例变量。

       为了解释这个程序,首先需要澄清一个概念,java对象是由构造器创建的吗?很多书籍,资料中会说是,但实际情况是:构造器只负责对java对象实例变量执行初始化,在执行构造器之前,该对象所占的内存已经被分配下来了,这些内存的值都默认是空值 ------对与基本类型的变量,默认的空值是0或者是false,对于引用类型而言就是null;当程序执行①代码时,系统先为Derived对象分配内存空间,有两块内存空间分别存放Derived对象的两个i实例变量,一个是属于Base的一个是Derived的,此时这两个i实例变量的值都是0;

       接下来程序在执行Derived类的构造器之前,首先会执行Base类的构造器,表面上看,Base类的构造器内只有一行代码 this.display();,但由于Base类定义了i实例变量时指定了初始值2,因此经过编译器处理后,该构造器应该包含如下两行代码。

      i  =  2;

      this.display();

     因此,程序现将Base类中定义的i实例变量赋值为2,再调用this.display();方法。此处有一个关键:this代表的是谁?在回答这个问题之前,先进行一个简单的修改,将Base类的构造器改为如下形式。

      public Base()

      {

            //直接输出this.i

           System.out.println(this.i);

           this.display();

       }

再次运行程序,将看到输出是2和0;看到这个结果,可能有人会更加混乱了,此时的this到底代表谁?

     当this在构造器中时,this代表正在初始化的java对象,此时的情况是:从源代码来看,此时的this位于Base()构造器内,但这些代码实际放在Derived()构造器中执行---是Derived构造器隐式调用了Base()构造器的代码,由此可见,此时的this应该是Derived对象,而不是Base对象。现在问题又出现了,既然this引用代表了Derived对象,那怎么直接输出this.i时会输出2呢?这是因为,这个 this虽然代表Derived对象,但它却位于Base构造器中,它的编译时类型是Base,而他/她实际引用了一个Derived对象,为了证实这一点,再次改写程序。

     为Derived类增加一个简单的sub()方法,然后将Base构造器改为如下形式。

public Base()
    {
        System.out.println(this.i);

        this.display();   

        System.out.println(this.getClass());

        this.sub();
    }

上面程序调用this.getClass()来获取this代表对象的类,将看到输出的是Derived类,这表名此时this引用代表的是 Derived对象,但接下来,程序通过this调用sub方法时,则无法通过编译,这就是因为this的编译时类型是Base的缘故。

   当变量的编译时类型和运行时类型不同时,通过该变量访问它所引用的对象的实例变量时,该实例变量的值由声明该变量的类型决定,但通过该变量调用它引用的对象的实例方法时,该方法行为由它实际所引用的对象来决定,一次当程序访问this.i时,它将访问Base类中定义的i实例变量,也就是将输出2;但执行 this.display()时则实际表现出Derived对象的行为,也就是输出Derived对象的i实例变量,即为0;



以上是通过资料查找到的,有问题欢迎指出来。希望对大家有所帮助吧。



---------------------- android培训、java培训、期待与您交流! ----------------------

详细请查看:http://edu.csdn.net/heima
1 楼 newcomes 2012-06-21   顿时感觉自己知道的太少了

热点排行