class A{
     public void a1(){....};
     public void a2(){....};
}class B extends A{
     public void a1(){....};
     public void b1(){....};
}public class C{
    public static void main(String[] args){
          A one = new B();
          one.a1();
          one.a2();
          one.b1();//error 
   }
}在上面的例子中,当一个父类变量引用子类对象时,该变量可以调用父类中定义的两个方法,却不可以访问子类特有的方法,这说明该变量只是能够访问子类实例的父类部分,但是a1()方法也被子类覆盖了,应该属于子类部分啊,该变量却可以访问a1(),而不能访问b1().
这是为什么???????
在堆中是如何划分子类和父类各自的部分呢?如果说子类中的a1()覆盖了父类中a1()后,成为基类部分,那么又为什么在子类a1()的实现中可以访问子类的域呢?说明不可能是基类部分.那这中间究竟是什么原因呢?请哪位高手帮小第看看,小第刚学java,有很多地方需请教各位高手!!!!!!!

解决方案 »

  1.   

    我想这是因为覆盖后的方法a1()不属于子类的特性,它在子类对象向上转型后,不会被认为是子类有别于父类的方法.只有子类中有,而父类中没的方法与域才会在转型中被转掉!
    从父类中继承的方法经转型后,就是子类的方法,自然可以访问子类的域.
    Thinking in Java讲的蛮详细的,你可以看一下!
      

  2.   

    首先解释一下:子类继承父类,并且覆盖父类方法,并不是说替换了父类中的同名方法而是把父类中的方法隐藏了。可以使用super关键字调用父类被覆盖的方法。
    java 实例源文件
    class A
    {
    public void fun1()
      {System.out.prinln("**");}
    public void fun2()
      {System.out.println("*****");}
    }
    class B extends A
    {
    public void fun2()
      {System.out.println("the B.fun2 is calling:"+"*****");}
    public void fun3()
      {System.out.println("#####");}}
    public class Test
    {
    public static void main(String arg[])
    {
    A one=new A();
    A two=new B();//在堆内存中生成B实例对象,在栈内存中定义了一个A类引用变量指向B实例对象
    one.fun1();
    one.fun2();
    two.fun1();
    two.fun2();
    //two.fun3();
    }
    }
    输出:
    **
    ****
    **
    the B.fun2 is calling:*****
    由结果可以看到,虽然堆内存中同样存在一个A类对象但是因为定义的A类引用变量指向的是内存中的B对象,在调用two.fun2();方法。指针two是到B对象内存中去调用。为什么不能调用fun3呢?
    因为定义two为A类引用变量本身就相当于标明two是父类类型的因此它的引用也要以父类为模版,超出的部分会被剔除。
      

  3.   

    这是多态问题,JAVA成员相当于C++中的虚函数,当子类继承了父类方法又在子类中定义了相同方法这叫做覆盖(override),下面来看看这三句 :
              A one = new B();
              one.a1();
              one.a2();
              one.b1();//error 
    用父类引用子类对象其实是这样的:可能(C++是这样的也许JAVA也是这样反正原理是一样的)
    class A{
         Hashtable vtable;(类似Hashtable的数据结构)
         public void a1(){....};
         public void a2(){....};
    }
    当对象访问成员函数是,是这样的:
    假如要访问a1()           JRE会根据a1()在类模板中的顺序来访问VTABLE
    a1()-------->vtable[a1函数的地址]----->真正的a1函数
    当发生覆盖调用时JRE会动态修改VTABLE中函数的地址,使之指向真正的函数。
    就像one.a1();指向子类的函数地址,因为子类中没有b1()函数,所以VTABLE中的地址为NULL所以会出错