A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 耿鑫 中级黑马   /  2012-6-19 12:51  /  4982 人查看  /  5 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 耿鑫 于 2012-6-19 13:55 编辑

看到一个程序题,拿出来和大家分享一下
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();
        }
}

输出的结果是什么? 为什么? 最主要的是为什么 ,放到eclipse中谁都知道结果。

5 个回复

倒序浏览
http://bbs.itheima.com/thread-17286-1-1.html
这个问题前两天李盼同学已经分析过了~!

评分

参与人数 1黑马币 +10 收起 理由
黄奕豪 + 10 你现在知道当版主的悲哀了吧,都是一样的问.

查看全部评分

回复 使用道具 举报
就我知道的这个问题在论坛里不下5个人问了;
i还没有来的及初始化;这个时候的i仍然是默认初始化的值;成员变量的值在对象的时候才会进行手动初始化;这个在new子类的时候去找到父类;并进行初始化;而这个时候的父类的成员变量都没有进行初始化;实际是打印的是父类的没有被初始化的值;
回复 使用道具 举报
好吧,既然有人分析过了 ,那么我把我的分析拿出来和大家分享一下,可能和他有出入

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();                                                  //①
    }
}

问输出的结果是什么?

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

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

       接下来程序在执行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;

评分

参与人数 1技术分 +1 收起 理由
黄奕豪 + 1 赞一个!

查看全部评分

回复 使用道具 举报
其实你不用去网上找那么多,你也说了eclipse下一运行就知道结果了,你Debug一下就知道具体执行的步骤了,然后就知道为什么了
首先会调用子类的构造函数  第一步执行:Derived(),但是并没有进方法内部,而是直接调用父类的构造函数Base(),这时候也不会进方法内部,而是先初始化变量i的值,但是注意了:这个i是父类的i,而不是子类内部的i,子类内部的i还是0,没有被初始化,然后进父类构造函数内部,疑惑就出在这里,这要弄明白这个this指的是谁,这个问题就好理解了
Debug中 this指的是子类对象,而不是父类,所以调用的肯定是自己的disPlay方法了 ,但是子类里的i的值还是0  所以打印出来的就是0 了
回复 使用道具 举报
我的理解和你的是一样的,查再多资料不如自己下手试一下,我debug了之后,发现输出结果是0 主要原因就是这个this代表的不是父类自己而是子类对象自己,并且在执行new的时候 子类里面有两个变量i 一个是继承下来的 一个是自己的,当new 的时候会先到Derived()这一步,但是不会进方法体,直接调用父类的构造函数Base(),这时候用debug就能很清楚看到 this指的 是子类对象 并且里面有两个变量i  当执行到父类构造函数时,会先执行变量i赋值这一步,这个时候父类的i就变成了22,然后进父类构造函数内部,注意了,因为this指的是子类,所以当然调用的是子类的disPlay函数,但是子类这时候i还没有没赋值 ,所以会输出0
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马