日期:2014-05-20  浏览次数:20799 次

关于Java继承的一个小程序,请教下高手
Java code

package temp;

class SubClass {
    int a = 1;
    public int getA(){
        return a;
    }
}

class ChildClass extends SubClass {
    int a = 2;
//    public int getA(){
//        return a;
//    }
}

public class Temp8 {
    public static void main(String[] args) {
                //(1) s,c都是指向子类的引用,它们的根本区别在哪里?
        SubClass s = new ChildClass();
        ChildClass c = new ChildClass();
                //(2)既然s,c都是指向子类的引用, 为什么s.a打印的是父类中的a,而c.a打印的是子类的?
        System.out.println(s.a);
        System.out.println(c.a);
                //(3)SubClass中的getA()既然会被继承,那么ChildClass中注释掉的部分,注释与否为什么会对结果产生影响?(不注释返回的是ChildClass中的a,注释掉返回的是SubClass的a)
        System.out.println(s.getA());
        System.out.println(c.getA());
    }
}




请大家来看看(1)(2)(3)这三个问题,先谢过

------解决方案--------------------
1, s,c 都是子类对象,只是 s 是用父类来声明, 子类来创建的对象
c 是子类声明并且创建的对象

2,用父类声明的子类对象, 只能用父类的属性和方法,子类的本身的属性和方法用的时候是看见不的,
而用这个对象调用父类方法时,如果子类重写了父类方法,那么执行的是子类的方法体 ,但属性还是父类的不变
这就是多态 (属性看声明,方法看对象)
所以,s.a 是父类声明的属性,a=1; c.a 是子类声明的属性 a = 2

s.getA() 是父类的方法,在子类中被重写了,因此执行子类的方法体 返回 2
c.getA() 本身就是子类声明创建的对象的方法, 返回值也是2

关于继承,如何楼主认可上述所说,那么请楼主 想明白 (属性看声明,方法看对象) 这句就可以了
并且,java的接口 声明 的多态 都是这么个意思





------解决方案--------------------
我也来说说我的理解:

输出结果: 1 2 1 1 

假如在ChildClass中加上getA()方法,输出结果:1 2 2 2 

1、一个是父类型的引用一个是子类型的引用,子类可以向上转型,父类不可以向下转。

2、SubClass s = new ChildClass();
ChildClass c = new ChildClass();
从这里可看出来,在JVM编译期的时候,只会认为S是 SubClass.class ,c 是 ChildClass.class ,也就是说s除了SubClass.class 意外的信息都不知道,而对于子类ChildClass.class 的成员都不知道,也就是说除了父类ChildClass.class 以外,s无法访问ChildClass.class的成员,s.a是绝对报错的

假如子类中有对父类方法的重写,那么根据多态机制,通过s访问这个方法的时候实际访问的是子类中重写的方法。

为什么这样可以?上面说了,s只能访问SubClass.class的信息(注意这里指的是编译期编译器只知道s是SubClass类型,不知道s具体指向什么对象,运行期才知道指向什么对象),而子类重写的方法,父类中也存在,即ChildClass.class重写的方法,SubClass.class里也有(如果ChildClass.class里有但是SubClass.class里没有的方法,s也不能直接调用),所以s可以访问,但是调用的时候(注意这里指的是运行期),s实际指向的是ChildClass对象,所以调用的是ChildClass对象的方法。

3、ChildClass 并没有重写SubClass 中的getA()方法,所以调用的是SubClass中的方法,而a在SubClass中的值为 1 ,故,s.getA() -->1

在此:

如果子类重写的方法中访问了专属于子类的成员变量,这时候通过父类引用s还可以调用那个被重写的方法吗?

要分清编译期和运行期,编译期是编译器检查语法和类型,运行期是解析器解析伪代码为机器指令而执行,编译期编译器会检查s的访问范围,也就是s的访问不超过SubClass.class的信息就不会出错,运行期解析器会解析方法的代码指令,因为s指向子类对象,所以会解析子类重写的方法代码指令,而子类对象的内存空间是包含子类的成员变量的空间的,所以也不存在子类成员变量没有分配内存的问题,所以可以调用。

  
再说 : 加上ChildClass中的getA()方法,也就是重写了父类的方法,而return a, 在ChildClass中a这个成员变量被重写了,所以 s.getA() -->2 c.getA() -->2

参考帖子:http://topic.csdn.net/u/20120613/11/4bd36b8d-2ce1-4640-9969-a8bd24fe20e1.html

以上是我结合自己的理解以及帖子的参考得到最满意的答案,请大家多多指点