java子类继承父类问题
求解释! 虽然做了几年的开发
但确实不明白为什么?
[code="java"]
class Foo {
public int a;
public Foo() { a = 3; }
public void addFive() { a += 5; }
}
public class Bar extends Foo{
public int a;
public Bar() { a = 8; }
public void addFive() { this.a +=5; }
public static void main(String[] args) {
Foo foo = new Bar();
foo.addFive();
System.out.println("Value: "+ foo.a);
}
}
[/code]
结果为什么输出的是3
可以试下~
求解释
[b]问题补充:[/b]
看到楼下的很多朋友的回答
我之前也是这么认为的
与java得多态有关 方法可以多态重载,但属性不能
假设这样设想 我想得到结果是
在父类的属性a的值的基础上 让其用子类的加法进行呢?
如何实现呢?
[code="java"]
public int addFive() {
super.a += 5;
}
[/code]
就可以了
[code="java"]class Foo {
public int a;
public Foo() {
a = 3;
}
public int addFive() {
a += 5;
return a;
}
public int getA() {
return a;
}
}
public class Bar extends Foo {
public int a;
public Bar() {
a = 8;
}
public int addFive() {
this.a += 5;
return a;
}
public int getA() {
return a;
}
public static void main(String[] args) {
Foo foo = new Bar();
//调用的是子类中的方法
System.out.println(foo.getA());
//直接调用父类中的a
System.out.println("Value: " + foo.a);
//调用的是子类中的方法
System.out.println(foo.addFive());
}
}[/code]输出结果:
8
Value: 3
13
楼主,只需要明白一点就行了:在Java中重写指的是方法的重写,而不是属性的重写,还有多态也只是方法的多态 ,没有属性的多态。
子类实例化的时候会调用它父类的默认构造方法
这个是java类初始化问题,每个子类对象都含有父类对象,所以要先调用父类的构造函数构造一个父类对象。
你可以看看:Java类初始化顺序
[url]http://red-xie.iteye.com/admin/blogs/258789[/url]
Foo foo = new Bar(); //实际上实例化Foo 类中的a = 3;
foo.addFive(); //实际上调用了Bar类的方法
如果是想得到 5 + 8 = 13的结果,就封装a字段
class Foo {
private int a;
public Foo() { a = 3; }
public void addFive() { a += 5; }
public int getA() {
return a;
}
}
public class Bar extends Foo{
private int a;
public Bar() { a = 8; }
public int getA() {
return a;
}
@Override
public void addFive() { a +=5; }
public static void main(String[] args) {
Foo foo = new Bar();
foo.addFive();
System.out.println("Value: "+ foo.getA());
}
}
Foo foo = new Bar();
像这种upcast(向上造型)
1.域:调用父类属性
2.方法:调用子类方法
这里 foo.addFive(); 调用子类的方法
有点值得关注的是。如果addFive返回类型改成int 之后
你打印System.out.println(foo.addFive());
的值是18,而不是13。
至于输出的是3
就是因为第一条,调用的是父类的属性。而跟方法无关。
[quote]详情见:thinking in java 4th 的例子
中文版156
英文版290[/quote]
主要的问题是你要理解子类重写父类方法会造成父类方法被覆盖,而属性却不是这样;
Foo foo = new Bar();
程序运行到这一部,是实例化一个子类对象交给父类引用,在这个对象中有两个属性a,父类的属性a=3和子类自己的a=8 ,而addFive方法只有一个,那就是子类重写的addFive方法;
foo.addFive();
这一步调用的是子类重写后的方法,所以在这里值发生改变的是子类的a而不是父类的,这时候子类的a=8+5=13,而父类的a=3没有变。
System.out.println("Value: "+ foo.a);
foo是一个父类的引用,foo.a是父类的a当然是等于3了
在子类中调用父类同名属性可以这样写super.a
其实去看Debug View的内存树会比较清楚。。。。
[quote]有点值得关注的是。如果addFive返回类型改成int 之后
你打印System.out.println(foo.addFive());
的值是18,而不是13。 [/quote]
晕。。我用了两次 foo.addFive(); 怪不得是18.
晕到我。
呵呵,虽然知道子类能override方法,不能override属性,但还是没做出来,羞愧。
楼上回答的很棒,方法是重写,属性不能重写。
注意:这句 Foo foo = new Bar();创建了一个Bar对象
一个对象创建的过程分成4步:
1.分配[color=red]总[/color]空间
2.递归创建父类对象
3.调用本类构造方法
4.初始化本类属性;
还有第2点 其实是创建了父类的属性和方法,并没有创建父类对象,用人们的眼光来把它
单独拿出来看,[color=red]像[/color]是创建了父类对象似的;
父类的除private方法以外的方法都被子类所继承.并且覆盖但是属性却没有被覆盖,所以foo.a 访问的是父类的 属性,而 foo.addFive(); 调用的是子类覆盖父类的 addFive()方法,既然调用的是子类的方法,所以这个方法修改的是子类属性的值
是的,分析得很好呢.......
分析得都很好,学习了
父类中的a和子类中的a是两个不同的成员变量,同时存在的,不会出现覆盖的现象。
Foo foo = new TestEYE1(); //调用父类构造。
此时,foo虽然是TestEYE1,但是它是被当作Foo来执行的。
所以它的一些TestEYE1属性全部都被禁用。但是堆中存在这些属性。
当调用
foo.addFive(); 方法时,由于子类对父类的方法重写,执行子类的方法,
this.a +=5; 其中this可以不加的,默认的就是调用本类(TestEYE1)的成员变量。
最后打印foo.a,foo虽然有两个a成员变量,但是因为它现在是Foo身份,所以子类的a是禁用的,但是它还是存在的,只要身份变成TestEYE1,就会打印子类的a属性。看第二次打印的结果就知道了。
System.out.println("Value: "+ foo.a);
System.out.println("Value: "+ ((TestEYE1)foo).a);
这个题目,如果楼主觉得混要,有一个简单的方法,把子类的a全改成b,就知道了。
因为对计算机而言,这两个成员变量就算是名字相同,它也认为不同的。
只要明白,这两个成员变量都存在就好理解了~
[code="java"]
Foo foo = new Bar(); //foo.a=3,bar.a=8
foo.addFive(); //bar.a=8+5
System.out.println("Value: "+ foo.a); //foo.a=3,bar.a=13
[/code]
这也是隐藏域,提供setter/getter的一个原因吧。
Foo foo = new Bar(); 此时,new的虽然是Bar()的实力,但是在内存看到的只是父类的方法跟属性,与子类无关。所以,a的值为3。
[quote]Foo foo = new Bar(); 此时,new的虽然是Bar()的实力,但是在内存看到的只是父类的方法跟属性,与子类无关。所以,a的值为3。[/quote]
子类的方法,父类的属性
不好意思,说错了。谢谢上面的纠正
受教了,好好学习。
Foo foo = new Bar();
就相当于Foo foo = new Foo();没什么区别!!
class Base{
public int a;
public static int b;
public Base(){
a=1;
b=1;
}
public void addFivetoa(){
a+=5;
}
public static void addSixtob(){
b+=6;
}
}
public class Son extends Base{
//public int a;
//public static int b;
public Son(){
a=2;
b=2;
}
public void addFivetoa(){
a+=5;
}
public static void addSixtob(){
b+=6;
}
public static void main(String args[]){
Son son = new Son();
Base base = son;
base.addFivetoa();
base.addSixtob();
System.out.println(base.a);//7
System.out.println(base.b);//8
System.out.println(son.a);//7
System.out.println(son.b);//8
}
}
过程:先初始化Base的b为0,然后调用父类的构造方法初始化a=1,b=1,然后调用Son的构造方法初始化a=2,b=2;
base.addFivetoa();//a=7;调用的子类的
base.addSixtob();//b=8;调用的父类的
属性是不能多态的,静态方法也不能多态。
图示:
[img] http://dl.iteye.com/upload/attachment/146753/1c112269-254f-3f9e-9bd4-afa547d99cd3.jpg[/img]
衍生:
Java代码
class Base{
public int a;
public static int b;
public Base(){
a=1;
b=1;
}
public void addFivetoa(){
a+=5;
}
public static void addSixtob(){
b+=6;
}
}
public class Son extends Base{
public int a;
public static int b;
public Son(){
a=2;
b=2;
}
public void addFivetoa(){
a+=5;
}
public static void addSixtob(){
b+=6;
}
public static void main(String args[]){
Son son = new Son();
Base base = son;
base.addFivetoa();
base.addSixtob();
System.out.println(base.a);//1
System.out.println(base.b);//7
System.out.println(son.a);//7
System.out.println(son.b);//2
}
}
过程:先初始化Base的b为0,然后调用父类的构造方法初始化a=1,b=1,然后调用Son的构造方法初始化子类中的a和b,a=2,b=2;
base.addFivetoa();//调用子类的方法,son.a=7
base.addSixtob();//调用父类的方法,base.b=1+6=7
剩下的base.a和son.b都没有变化所以分别为1,2。
其中加粗红色的1是父类的b的值,base.addSixtob()(是静态的)所以要调用addSixtob()所在类base的b的值也就是,或者说是base对象调用了addSixtob(),所以要访问base对象所在类的b值。
图示:
[img]http://dl.iteye.com/upload/attachment/146760/ab3a1b28-06a7-3ac3-b126-b9aea00225cf.jpg[/img]