class A
{
String name="张三";
void qq(A a)
{
System.out.println(a.name);
}
public static void main(String args[])
{
A a=new A();
B b=new B();
a.qq(b);
}
}
class B extends A
{
String name="李四";
}
请问一下,上面的程序为什么会输出张三啊?我是这么想的:B类继承了A类,并覆盖了A类的成员变量
name,a.qq(b)传递过去的是B类的实例,应当输出李四啊?

解决方案 »

  1.   

    b虽然是B的实例,但使用a.name的时候,因为a是用A来引用的,Java会使用A类自己声明的实例变量name,因为父类对子类的内部是一无所知的。
    还有就是访问一个对象的变量,这个没有覆盖不覆盖的说法,父类和子类都有一个name变量,在不同的内存地址,互不影响。
      

  2.   

    此时,子类对父类的属性不是复写,而是隐藏,即内存中其父类A的属性name并没有消失,只是被隐藏罢了,如果子类B定义了qq()方法则,调用时会显示 李四,即子类B自己的属性值,但子类没有定义qq()方法,它之所以能使用该方法完全继承自其父类A,因此,这时它显示的只是被其隐藏的其父类A的属性NAME值!
      

  3.   

    我认为你说的不对:例如下面的程序会输出"王刚";
    class A
    {
    String name="张三";
    A()
    {
    name="王刚";
    }
    void qq(A a)
    {
    System.out.println(a.name);
    }
    public static void main(String args[])
    {
    A a=new A();
    B b=new B();

    a.qq(b);
    }
    }
    class B extends A
    {
    B()
    {
    super();
    }
    String name="李四";
    }
      

  4.   

    您说的还原点道理,但是"在头带哥"纯是胡扯,它说:"如果子类B定义了qq()方法则,调用时会显示 李四,"
    我测试了,不会输出李四,还是输出张三.程序如下:
    class A
    {
    String name="张三";
    void qq(A a)
    {
    System.out.println(a.name);
    }
    public static void main(String args[])
    {
    A a=new A();
    B b=new B();
    a.qq(b);
    }
    }
    class B extends A
    {
    void qq(A a)
    {
    System.out.println(a.name);
    }
    String name="李四";
    }
      

  5.   

    class A
    {
    String name="张三";
    void qq(A a)
    {
    a.show();
    System.out.println(a.name);
    }

    public void show(){
    System.out.println("a   "+this.name);
    }
    public static void main(String args[])
    {
    A a=new A();
    B b=new B();
    a.show();
    b.show();
    a.qq(b);
    }
    }
    class B extends A
    {
    String name="李四";
    public void show(){
    System.out.println("b   "+this.name);
    }
    }
      

  6.   

    这个和继承没有关系,这里的问题是函数调用会选择哪个参数的问题
    class A
    {
      String name = "张三";//A.name
    }
    class B extends A
    {
      String name = "李四";//B.name
       //这里注意,B其实还有一个继承下来的name成员,如果需要使用可以通过super.name来引用。
    }
    class MainClass
    {
      private static void outA(A a)
    {
    System.out.println("a   "+a.name);
    }
    private static void outB(B b)
    {
    System.out.println("b   "+b.name);
    }
    public static void main(String[] args)
    {
      B b = new B();
      outA(b);//输出张三,输出了b的隐藏成员
      outB(b);//输出李四,输出了b的新成员
    }
    }
    所以这里输出什么取决于你将它当作什么类型处理
      

  7.   

    这东西说来话就长了,话说那天LZ学习JAVA搞了个例子考考编译器的,编译器一看就开工了,可到了a.qq(b)这一句怎么运行呀,编译器这时被LZ逼得,就差没跳墙了,它先找到函数的声明,这时发现要一个A这样的参数,结果发现里面只有B,当时这个编译器急得,仔细一看,原来B就是A的儿子呀,编译器对B就找不到你老子就拿你顶了,结果就把B扔进去运算了,结果B这小子进去一看,kao打印我老子的名字呀,于是就把他老子的名字招了,所以结果就成......
      

  8.   

    jvm中,处理方法和属性确实不一样.
    除了私有方法和静态方法,对于其他方法,jvm中有个表,这个表类似于c++里的虚函数表Vtable,在调用方法时,根据实例的类型,从表中确定应该调用哪一个,这样就实现了覆盖基类中方法的能力.
    但是对于属性,没有上面这一说,任何一个属性在编译结束时即可确定其地址.换句话说,属性没有覆盖这一说.
    一楼说的也是对的,但是没说到本质上.二楼是错的.
      

  9.   

    不知道用C++中的翻译期绑定机制来解释会不会好一点!!
    虽然java和c++不一样但是在许多方面是相通的!
    回来程序来说吧:qq(A a )方法调用的参数是A类型的,在翻译期间就约定了参数A的类型,尽管被赋于B类型,jvm依然会使用翻译期间的初衷一样,认为是A类型,结果是哪样就可想而知了