黑马程序员技术交流社区

标题: 继承成员变量和继承方法的一些疑问 [打印本页]

作者: dev    时间: 2012-6-29 16:46
标题: 继承成员变量和继承方法的一些疑问
本帖最后由 翁游龙 于 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,这里很费解?




作者: 孙浩迪    时间: 2012-6-29 17:24
变量是不能被继承的。。。  变量是个特殊。。。。

老毕说过啊,调变量看左边,调方法看右边。
作者: 赵方明    时间: 2012-6-29 17:33
本帖最后由 赵方明 于 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

作者: 游洪波    时间: 2012-6-29 17:38
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)-----");
        }
}

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

第四段 其实是一样的道理  




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2