class Foo { 
public Integer a; 
public Foo() { a = 3; } 
public void addFive() { a += 5; } 

public class Bar extends Foo { 
public Integer a; 
public Bar() { a = 8; } 
public void addFive() { a +=5; } 
public static void main(String[] args){
Foo f=new Bar();
f.addFive();
System.out.println(f.a);
}
} 为什么这个的输出结果是3;请详细解释,谢谢

解决方案 »

  1.   

    public static void main(String[] args){
    Bar b = new Bar();
    Foo f = b;
    f.addFive();
    System.out.println(f.a);
    System.out.println(b.a);
    }我把代码改了下,楼主再看看吧,呵呵。
      

  2.   

    Foo f=new Bar();  父类类型的引用指向子类的实例 
    当执行new Bar()的时候会调用Bar类的构造方法,而在Bar()方面里面会调用父类的构造方法,所以此时Foo类里面的a是3,Bar类里面的a是5, Bar类重写了Foo类的addFive()方法,由于会产生多态,所以f.addFive()是执行的Bar类的addFive(),操纵的是Bar类自己的a.而不是父类的.
    最后你输出的是f.a  由于字段是不会产生多态的,所以这里还是会输出Foo类的a.!所以结果是3.! 
      

  3.   

    f向上转型为Foo引用时,任何域访问操作都将由编译器解析,不是多态性.
      

  4.   

    f向上转型为Foo引用时,任何域访问操作都将由编译器解析,不是多态性.
      

  5.   

    自己写个JUnit终于明白了。
    字段是不会产生多态,2楼正确。
      

  6.   

    Foo f=new Bar();  //Foo的父类应用指向了一个Bar的实例,调用了父类的构造函数
    f.addFive();   //执行的是子类实例的重写方法,被加5的是bar实例中的a
    System.out.println(f.a);   //f.a始终是3,没有变过
         
      

  7.   


    Foo f = new Foo();
    f.addFive();
    System.out.println(f.a);为什么这样运行出来结果是8,而Foo f=new Bar();
    f.addFive();
    System.out.println(f.a);结果是3,区别在哪里?
      

  8.   

    因为  Bar继承了Foo  
    Foo f=new Bar();   这个new Bar()  首先会去调用父类的构造函数   而父类的构造函数  a=3
      

  9.   

    class Foo { 
    public Integer  a=0; 
    public Foo() { 
    System.out.println("执行父类构造方法");


    a = 10+a;


    public void addFive() { a += 5; } 

    public class Bar extends Foo { 
    public Integer a=0; 
    public Bar() {
     System.out.println("执行子类构造方法");

     a =20+a; 


    public void addFive() { a +=5; } 
    public static void main(String[] args){
    Foo ff = new Bar();
    Bar f = new Bar();
        f.addFive();
        System.out.println(ff.a);
        System.out.println(f.a);
    }

    输出结果为:
    执行父类构造方法
    执行子类构造方法
    执行父类构造方法
    执行子类构造方法
    10
    25
    希望对楼主理解问题有所帮助!
    关于初始化的顺序,可以考虑用eclipse断点跟踪!
      

  10.   

    啊,想明白了Foo f = new Bar();
    f.addFive();    //运行Bar中的方法,改变Bar中a的值,Foo中a的值不变
    System.out.println(f.a);   //输出3Foo f = new Foo();
    f.addFive();  //运行Foo中的方法,改变Foo中a的值
    System.out.println(f.a);   //输出8
      

  11.   

    其实只要记住一点,多态只是方法的多态,不涉及变量。具体回到这题目的话其实就是Foo的变量当在使用变量的时候用的是Foo的变量,而使用到方法的时候其实虚拟机会判断具体的类型是什么?然后就调用对应的方法
      

  12.   

    大家debug一下就明白了。
    debug这个功能好强大。跟踪程序执行的过程。
      

  13.   


    一楼问个问题!你这个Foo f = b;能不能解释下!是说有个Foo的引用f现在指向了b的内存空间?
      

  14.   


    Foo f=b  这只是赋值语句...
      

  15.   

    Foo f=b,其实是个类型的转换,只不过是隐式转换
      

  16.   

    Foo f=b,其实是个类型的转换,只不过是隐式转换
      

  17.   

    Foo.a跟Bar.a不是一个a,成员变量只有隐藏(hide),没有覆盖(override)。
    但成员函数有覆盖,因此执行的是Bar的addFive。
    于是这个程序的效果就变成了:把Bar.a加上5,然后打印Foo.a。
      

  18.   

    声明Foo f的时候,调用了Foo类中的构造,完成了Foo类中a的初始化。
      

  19.   

    bar继承foo  f.a其实就是super().a;而父亲  中的a a的值就是
      

  20.   

    new Bar() 的时候会有两个a变量,一个是自己的,一个是超类的初始化为3 ,当掉用方法addFive 时 :f指向的是 Bar的一个实例,所以调用的是Bar 里面的方法 改变了Bar的变量a的值,而另外一个超类的初始化为3的值没有改变。
      

  21.   

    f.a在编译的时候就已经确定了,它不具有多态性,是编译器绑定,在编译的时候已经确定调用的就是父类的a成员
      

  22.   

    public static void main(String[] args) {
    Bar b = new Bar();
    Foo f = b;
    f.addFive();//实现了动态绑定,编译器从子类中中该方法,如果找不到,再去父类中找这个方法.(Bar中的a被加上5(8+5),而Foo中的a没有改变值,还是(a=3)).
    System.out.println(f.a);//字段没有多态,所以指向的是父类总的a变量(此时Bar中的a是13,只是没有打印)
    System.out.println(b.a);//此时Bar中的a是13
    }
      

  23.   

    public int addFive() { return a += 5; } 

      

  24.   

     
    class Foo { 
    public Integer a; 
    public Foo() { a = 3; } 
    public void addFive() { a += 5; } 

    public class Bar extends Foo { 
    public Integer a; 
    public Bar () { a = 8; } 
    public void addFive() { a +=5; } 
    public static void main(String[] args){
        Bar f=new Bar ();
        Foo f1=new Bar ();
        f1.addFive();
        f.addFive();
        System.out.println(f.a);
        System.out.println("这个a是和父类绑定的:"+f1.a);
        System.out.println("这个是和子类对象的实例绑定的:"+new Bar ().a);
    }

    这个就是涉及到多态,java虚拟机的绑定机制:
    1、成员变量(静态和非静态)和静态方法都是和所声明的类型绑定(静态绑定,在编译期就绑定了)如你开始声明类型是FOO类型的,所以a和父类绑定。
    2、实例方法是和实际声明的对像绑定的(动态绑定,运行时进行绑定),所以你调用的时候就是调用的子类的addFive()方法,这个就是原因了。不知道对不?