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;请详细解释,谢谢
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;请详细解释,谢谢
Bar b = new Bar();
Foo f = b;
f.addFive();
System.out.println(f.a);
System.out.println(b.a);
}我把代码改了下,楼主再看看吧,呵呵。
当执行new Bar()的时候会调用Bar类的构造方法,而在Bar()方面里面会调用父类的构造方法,所以此时Foo类里面的a是3,Bar类里面的a是5, Bar类重写了Foo类的addFive()方法,由于会产生多态,所以f.addFive()是执行的Bar类的addFive(),操纵的是Bar类自己的a.而不是父类的.
最后你输出的是f.a 由于字段是不会产生多态的,所以这里还是会输出Foo类的a.!所以结果是3.!
字段是不会产生多态,2楼正确。
f.addFive(); //执行的是子类实例的重写方法,被加5的是bar实例中的a
System.out.println(f.a); //f.a始终是3,没有变过
Foo f = new Foo();
f.addFive();
System.out.println(f.a);为什么这样运行出来结果是8,而Foo f=new Bar();
f.addFive();
System.out.println(f.a);结果是3,区别在哪里?
Foo f=new Bar(); 这个new Bar() 首先会去调用父类的构造函数 而父类的构造函数 a=3
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断点跟踪!
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
debug这个功能好强大。跟踪程序执行的过程。
一楼问个问题!你这个Foo f = b;能不能解释下!是说有个Foo的引用f现在指向了b的内存空间?
Foo f=b 这只是赋值语句...
但成员函数有覆盖,因此执行的是Bar的addFive。
于是这个程序的效果就变成了:把Bar.a加上5,然后打印Foo.a。
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
}
}
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()方法,这个就是原因了。不知道对不?