java子类继承父类问题

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]