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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© dev 中级黑马   /  2012-6-29 16:46  /  2658 人查看  /  5 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 翁游龙 于 2012-6-29 16:48 编辑

关于以下代码有两个疑问,请高手指点:

class Base{
        int count = 2;
        public void display(){
                System.out.println(this.count);
        }
}


class Derived extends Base{
        int count = 20;
        @Override
        public void display(){
                System.out.println(this.count);
        }
}


public class FieldAndMethodTest{
        public static void main(String[] args){
                //声明并创建一个Base对象
                Base b = new Base();
                System.out.println(b.count);
                b.display();
                System.out.println("-----(1)-----");


                //声明并创建一个Derived对象
                Derived d = new Derived();
                System.out.println("d.count = " + d.count);
                d.display();
                System.out.println("-----(2)-----");


                //声明一个Base变量,并将Derived对象赋给该变量
                Base bd = new Derived();
                System.out.println(bd.count);
                bd.display();
                System.out.println("-----(3)-----");


                //让d2b变量指向原d所指向的Derived对象
                Base d2b = d;
                System.out.println("d2b.count = " + d2b.count);
                System.out.println("-----(4)-----");
        }
}

运行结果为:

2
2
-----(1)-----
d.count = 20
20
-----(2)-----
2
20
-----(3)-----
d2b.count = 2
-----(4)-----


问题:
1、前面两段的输出是毫无疑问的,问题是为什么第三段这里,Derived继承了Base,
输出结果一个是2,另一个是20呢?结果不是应该都为20吗?这里不是很明白。

2、另外一个问题:第四段这里d2b和d指向同一个对象,可是访问d.coount时输出20,
而访问d2b.count时却输出2,这里很费解?



5 个回复

倒序浏览
变量是不能被继承的。。。  变量是个特殊。。。。

老毕说过啊,调变量看左边,调方法看右边。
回复 使用道具 举报
本帖最后由 赵方明 于 2012-6-29 17:35 编辑

class Base{
        int count = 2;
        public void display(){
                System.out.println(this.count);
        }
}


class Derived extends Base{
        int count = 20;
        @Override
        public void display(){
                System.out.println(this.count);
        }
}


public class FieldAndMethodTest{
        public static void main(String[] args){
                //声明并创建一个Base对象
                Base b = new Base();
                System.out.println(b.count);
                b.display();
                System.out.println("-----(1)-----");


                //声明并创建一个Derived对象
                Derived d = new Derived();
                System.out.println("d.count = " + d.count);
                d.display();
                System.out.println("-----(2)-----");


                //声明一个Base变量,并将Derived对象赋给该变量
                Base bd = new Derived();
                System.out.println(bd.count);
                bd.display();
                System.out.println("-----(3)-----");


                //让d2b变量指向原d所指向的Derived对象
                Base d2b = d;
                System.out.println("d2b.count = " + d2b.count);
                System.out.println("-----(4)-----");
        }
}
第一个和第二个,编译类型和运行类型是一样的,不涉及多态。
老毕在第八天多态中成员的特点时讲了的。
你混淆了成员函数和成员方法。
在多态中成员函数的特点时:
在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。
在运行时期:参阅对象所属的类中是否有调用的方法。
简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。

而成员变量
无论编译和运行,都参考左边(引用型变量所属的类)。
System.out.println(bd.count);
System.out.println("d2b.count = " + d2b.count);
bd.count和d2b.count都将调用它们声明时类型,也就是Base类型中的count,输出结果为2

评分

参与人数 1技术分 +1 收起 理由
刘蕴学 + 1

查看全部评分

回复 使用道具 举报
class Base{
        int count = 2;
        public void display(){
                System.out.println(this.count);
        }
}


class Derived extends Base{
        int count = 20;
        @Override
        public void display(){
                System.out.println(this.count);
        }
}


public class FieldAndMethodTest{
        public static void main(String[] args){
                //声明并创建一个Base对象
                Base b = new Base();//创建Base父类对象,这个时候和子类没有任何关系
                System.out.println(b.count);//你现在输出的count属性是父类中的属性所以输出了2
                b.display();//display方法也是父类中的方法所以这个方法输出的也是2,这样你能理解吧
                System.out.println("-----(1)-----");


                //声明并创建一个Derived对象
                Derived d = new Derived();//创建Dervied子类对象,这个子类虽然继承了Base类但是,在这里又把父类中的count属性的值覆盖成了20,并且实现了父类的display方法
                System.out.println("d.count = " + d.count);//这个时候count虽然是父类继承下的但是,count的值被子类中重新赋值为20,所以这里输出了20
                d.display();//这个方法也是输出了count的值所以同理也是20
                System.out.println("-----(2)-----");


                //声明一个Base变量,并将Derived对象赋给该变量
                Base bd = new Derived();//这点有点不同了,他使用了一次向上转型,即把子类对象赋给了父类。
                System.out.println(bd.count);//这个使用应为bd是父类对象所以调用的属性是父类中的属性,所以这里输出的是2
                bd.display();//这个方法本应该输出2的但是因为子类重写了父类的display方法所以这里使用的是子类的displaay方法,而子类的display方法输出的又是子类的count属性,所以这个地方是20
                System.out.println("-----(3)-----");


                //让d2b变量指向原d所指向的Derived对象
                Base d2b = d;//这个和上边那个是一样的也是一次向上的转型,是把子类的实例赋给了父类对象。
                System.out.println("d2b.count = " + d2b.count);//所以这个地方还是父类的count属性,所以为2
                System.out.println("-----(4)-----");
        }
}

点评

这问题能加2分?  发表于 2012-6-29 22:53

评分

参与人数 1技术分 +2 收起 理由
刘蕴学 + 2

查看全部评分

回复 使用道具 举报
Base bd = new Derived();  对象bd是子类Derived变量的上转型对象。
上转型对象具有如下特点。
1.上转型对象不能操作子类申明定义的成员变量所(失掉了这部分属性),不能使用使用子类声明定义的方法(若子类重写的方法是实例方法,那么上转型对象调用重写的方法);
所以调用 bd.display();  输出的是 20
2.上转型对象可以调用子类继承的成员变量和隐藏的成员变量  所以调用  bd.count  输出的是 2
3.可以将对象的上转型对象再强制转换成一个子类对象,此时该子类对象又具备子类的所有属性。
例如 Derived derive = (Derived)bd;
此时再输出 derive.count = 20;
回复 使用道具 举报
你的第三段的疑问:首先你定义了一个父类对象指向子类对象,这就是我们查常说的上转型对象,上转型对象指向子类对象的引用的时候,只能保留子类从父类那里继承过来的东西,不能访问子类对象特有的东西,这里count就是子类特有的东西,你Debug时会发现,子类有两个count  一个是继承过来的一个是他自己特有的,父类的对象只能访问它继承给儿子的那个count 也就是2  而儿子的他访问不到

第四段 其实是一样的道理  
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马