class A
{
String name="张三";
int age=30;
void qq()
{
System.out.println("第一次");
}
public static void main(String args[])
{
    A x=new B();
    System.out.println(x.name);
x.qq();
}
}
class B extends A
{
int age=20;
void qq()
{
System.out.println("第二次");
}}请问一下,上面申请了一个A类的引用X指向B类的实例,为什么x.name是访问A类的成员变量,而x.qq()是访问B类的成员方法.我是这么认为的,引用X要么都访问A类的成员变量,和成员方法,要么都访问B类的成员变量和成员方法,怎么交叉访问了,请问一下,有什么规律吗?
请大家给我说一下它的运行机制好吗?谢谢.

解决方案 »

  1.   

    好好看看java的继承那部分吧...
    你这叫'方法的覆盖',也就是说b类重写了a类的方法,所以实例化b的时候,a类的qq()已经被覆盖了....
      

  2.   

    你好,我看\书了,就是不明白,才上类问的,你说的一点都没有错:"你这叫'方法的覆盖',也就是说b类重写了a类的方法,所以实例化b的时候,a类的qq()已经被覆盖了....
    "
    但是,不知道,你仔细看了没有,B类中的age同样也覆盖了A类中的age为什么输出的时候,还是访问了A类中的age呢,按照你说的这种原则,应当访问B类中的age才对啊?
    不要叫我回去看书了,谢谢你,有些东西书上没有啊.
      

  3.   

    怎么不可以呢?我下的下面的这个例子可以证明:
    不好意思,也许我的认为是错误的,不过我一直这么认为的,如果错了,今天请你给你出,小弟不胜感激.]
    class A
    {
    String name="九天玄狐";
    public static void main(String args[])
    {
    B b=new B();
    System.out.println(b.name);
    }
    }
    class B extends A
    {
    String name=" JAVA 民工";//重写父类中的name属性.
    }
      

  4.   

    class A
    {
    void qq()
    {
    System.out.println("第一次");
    }
    public static void main(String args[])
    {
    A a=new A();
    a.qq();//再按照"九天玄狐"的思路来,这个地方应当输出"第二次",实际上输出了"第一次",证明了"九天玄狐"的看法有问题.
    }
    }
    class B extends A
    {
    void qq()
    {
    System.out.println("第二次");
    }
    }
      

  5.   

    方法的重写,当上付造型时用父类class引用子类对象时,此引用只能调用从父类中继承的方法和overreading的方法,如某一方法被ovrereading则调用重写后的方法.父类引用子类对象只能调用从父类中继承的属性,而不会调用overreading后的属性,如某一属性被ovrereading,父类引用还是使用重写前的属性.
    从另一个角度来考虑,虚拟机,父类会开辟一块空间来存放他的实例成员,子类是在父类的基础上,对父类的空间进行了新的扩展,这种扩展并不会消除父类已经实例的成员.
    最后一顶了....
      

  6.   

    这是JAVA多态性的一种表现,由于B类继承自A类,所以你x可以调用A类的属性;也正是因为多态,B类的qq()方法覆盖了其父类A的qq()方法.所以会打印"b.qq()"内的东东
      

  7.   

    hljhljhj 你好:
    您说:"也正是因为多态,B类的qq()方法覆盖了其父类A的qq()方法.所以会打印"b.qq()"内的东东
    "
    那么:B类的age也同样覆盖了其父类的age属性.为什么不会打印b.age()内的东东.
    如果方便还是想请你介绍一点有关内存结构方面的东东,我很想知道.期待你的回答.
      

  8.   

    楼上的楼上的朋友(joejoe1991),你好,首先感谢您对本贴的关注:
    以前是我理解错了应当是:父类的属性相对于子类来说只是隐藏了.(您的回答是正确的)
    方法是覆盖对吗?如果这样的话,为什么子类覆盖了父类中的方法,此时还能再一次的调用父类中的方法呢?如下:不好意思,你千万不要生气,也许是我太笨的原因吧<
    class A
    {
    void qq()
    {
    System.out.println("a");
    }
    public static void main(String[]args)
    {
    B b=new B();
    b.qq();
    }
    }
    class B extends A
    {
    void qq()
    {
    super.qq();
    }
    }
      

  9.   

    这是java 中继承的概念
    子类的对象在调用方法和成员变量时,先要从子类本身找起,如果自己类中有这个方法则使用子类自己的方法,如果没有才会找到父类的方法.这就是方法的重写.继承中很重要的特征.
      

  10.   

    如果你确实需要去改变他的默认调用,而去访问父类的方法,可以使用super访问父类的方法
      

  11.   

    很不好意思,大家回答了这么多的问题,但是没有回答到我所希望的目的上,不好意思,现在还不能结帐,"zp8126"你说的很好,关键是现在我们不是讨论的你这个问题.我们讨论的是:
    A类为B类的父类:
    A a=new b();
    a.属性:(访问谁的属性,为什么)
    a.方法:(访问谁的方法.为什么)
      

  12.   

    class A
    {
    String name="张三";
    int age=30;
    void qq()
    {
    System.out.println("第一次");
    }
    public static void main(String args[])
    {
        A x=new B();   //这里改成B x=new B();是一样的,创建对象是A,但是开内存的时候只开了B所需要的
        System.out.println(x.name);  //这里显然是张三
    x.qq();    //因为内存中只有B的空间,所以访问的是B的方法
    }
    }
    class B extends A
    {
    int age=20;
    void qq()
    {
    System.out.println("第二次");
    }把主方法放到B里面看着就顺些,理论上是一样的,结果也一样,如下:
    class A
    {
    String name="张三";
    int age=30;
    void qq()
    {
    System.out.println("第一次");
    }

    }
    class B extends A
    {
    int age=20;
    void qq()
    {
    System.out.println("第二次");
    }
    public static void main(String args[])
    {
        A x=new B();  
        System.out.println(x.name);  
    x.qq();
    }
    }
      

  13.   

    简单的说呢,当
    A x = new B();这个时候方法就看B的,成员变量就看A的
      

  14.   

    http://bbs.chinaunix.net/viewthread.php?tid=965826&extra=page%3D1
    看一下这个,应该就容易理解了。
      

  15.   

    class A{
        public String f(D obj){return ("A and D");}
        public String f(A obj){return ("A and A");}
    }
    class B extends A{
        public String f(B obj){return ("B and B");}
        public String f(A obj){return ("B and A");}
    }
    class C extends B{}
    class D extends B{}class TestComplexPoly{
        public static void main(String[] args){
            A a1 = new A();                     
            A a2 = new B();
            B b = new B();
            C c = new C();
            D d = new D();
            //System.out.println(a1.f(b));  // A and A
            //System.out.println(a1.f(c));   //A and A
            //System.out.println(a1.f(d));   //A and D
    --------------------------------------------------------------
            System.out.println(a2.f(b));   //B and A
            System.out.println(a2.f(c));   //B and A
            问题就是这两个为什么会是B and A 呢
    --------------------------------------------------------------        //System.out.println(a2.f(d));   //A and D
            //System.out.println(b.f(b));    //B and B
            //System.out.println(b.f(c));    //B and B
            //System.out.println(b.f(d));    //A and D                                              
        }
    }你研究一下这段代码.
      

  16.   

    楼上这几段代码,用我刚写的这个Java对象模型完全可以解释清楚。
    不明白的请看:
    http://bbs.chinaunix.net/viewthread.php?tid=965826&extra=page%3D1
      

  17.   

    学习ing
    正好看见这了,顶下
      

  18.   

    楼主对方法覆盖应该是有了解了,我就不多说了,我只针对那个父类与子类属性相同的问题谈我的看法。首先要明白:
    每个对象都在内存中有自己的区域。
    当一个子类对象实例化之后,那么也就意味着其父类的所有属性也被实例化了。
    方法在内存的一片区域,属性值存在于另一片区域,当执行方法调用时,CPU根据方法入口地址找到方法的位置,并执行方法。父类的方法在一片区域,子类的方法在另一片区域,如果调用一个子类对象的方法,CPU会去寻找这个方法的入口,它首先在子类对象的区域内找,如果找到了就执行,没有找到就去父类的方法区域找,然后是祖父,曾祖父直到找到为止,如果你深入了解了这个机制,那么所谓的方法重写的低层实现也就是这么简单而已。这么看来所谓的重写的方法其实在内存中的表现仍旧不是同一方法。(即,即使子类与父类有相同的方法签名,但它们是两个不同的方法)那么如果父类与子类的有同名的属性怎么办?其实看上去属性好像是相同的,但实际上这也是两个不同的属性,分别存在于不同的内存区域(当然,肯定都在一个对象的内存区域内)。请看这段代码:
    public class A {    String name = "zhangShan";
        protected int age = 20;    public static void main(String[]args)
        {
            B b=new B();
            System.out.println(b.getAge());
            System.out.println((new B()).getParentAge());
            b.printlnParentAge();
            
            A a = new B();
            System.out.println(a.age);
        }    public int getAge() {
            return this.age;
        }
    }class B extends A {
        int age = 10;    public void printlnParentAge() {
            System.out.println(super.age);
        }    public int getParentAge() {
            return super.age;
        }
    }你猜猜它会出什么样的结果呢?
    20
    20
    20
    20
    都是父类的age属性值。super.age指示是父类的那个属性age, 那个从父类继承来的方法,getAge()得到的仍旧是父类的age属性。属性的操作和方法的操作不太一样,它不会像方法操作那样根据类的层次的结构寻找最适当的方法入口。你可这样认为,它使用一种“直接”的策略寻找一个属性地址。因为JVM没有在B中找到getAge方法,就到父类A中寻找,它直接地操作了A的age属性.
    我们把程序改一下。就是在类B中加重写A的getAge方法。
    class B extends A {
        int age = 10;    public void printlnParentAge() {
            System.out.println(super.age);
        }    public int getParentAge() {
            return super.age;
        }
        
        public int getAge() {
            return age;
    }
    这时你使用
    B b = new B()
    print b.getAge
    得到的结果就是10了
    在程序执行的时候,JVM首先找到了B中的getAge方法,运行之,返回B的age值。再看一个:   
    A a = new B();
    print a.age
    输出的是20,它不管具体a对象到底是个什么玩意儿,反正JVM发现了a.age的属性。
    如果要输出“真正的”age属性怎么办?强制转换:
    A a = new B();
    print ((B)a).age
    这下就是10了,你使用强制转换告诉JVM你要的是子类的age属性。我大学学的一些东西有点忘了,以上是根据我还记得的一些知识推测的,属于个人观点。PS:同志们,不要以为学软件工程会个编程就也不起了,许多东西要理解起来,你没有微型计算机原理就是不行,你操作系统学得不好,学多线程就困难,你写测试类,不会测试原理你写的测试类就是垃圾... ...
    还有我们微型计算机的老师说的一句话很有道理:自学能力强的人就是那种能把事情说圆的人。
    有什么问题不懂,查些资料,资料看得差不多的时候,推敲一下,发现你把那不懂的东西说圆了,你就“懂”了。再写点BLOG去“找骂”,一定能真懂。
      

  19.   

    希望:"ZW_Ren(任再旺)"把写好的图片发到
      

  20.   

    to  xiongchenyan
    看我上面发的那个链接就行了,我把帖子发到别的论坛了。这里不能发图。
      

  21.   

    您所画的对象模型的图片,我稍微做了一些修改,和评论,您看一下我的看法对吗?
    我把图片放在:http://images13.51.com/26/a/9e/a9/renqiang_888/724_1024_356569950b779c52.jpg请点击放大镜查看.
    同时更希望有经验和了解对象模型的朋友能指点迷津.谢谢
      

  22.   

    各位显然答非所问, 而询问的人又给错了例子源码.楼主问"怎么交叉访问了", 实在没有看出来什么地方交叉访问, 楼主提到age的问题,源码里面根本没有访问age.访问都是访问子类以及子类继承的方法和属性
      

  23.   

    thinking in java--上传与下传,多态。
      

  24.   

    I can't believe this question will attack so many persons attention.
    unbelieveable.
      

  25.   

    1.你要清楚在A中
         String name="张三";       已经给对象赋值了
      就是说如果你new A(),而在A的构造函数里没有对name另外赋值,那name就会用默认的张三
    2.B是继承自A,如果B没有重新定义name,就会使用A中的name
      

  26.   

    Or does your intelligence quotient have a problem?Ha ha!
      

  27.   

    b.qq()隐藏了a.qq()当然访问的是b的方法了,这个书上好象写的有