关于继承,请解释下原因

public class Father {

private int i = 1;
public void p(){
    System.out.println(this.i);
}

}

public class Son extends Father {
private int i = 10;
public void q(){
System.out.println(this.i);
}
}

public class Main {

/**
 * @param args
 */
public static void main(String[] args) {
    Son son = new Son();
    son.p();
}

}

输出为1 是什么原因呢?
[b]问题补充:[/b]
我DEBUG过this this的值是子类的对象,却没有去得到子类的成员变量 所以才会有了这个简单的问题 希望大家帮我解答

[b]问题补充:[/b]
我在Father类里写了个方法
public void s(){
System.out.println(this.getClass().getName());
}

结果为Son,证明this确实是子类的对象
[b]问题补充:[/b]
[quote]Son的内存地址空间其实是有两个变量i,一个是从父类继承来的,一个是自己声明的,
[/quote]

这个事理解的

[quote]
当调用父类的方法时,此时的进入的堆栈地址空间是父类的地址空间
[/quote]

这个怎么保证??或者怎么实现??我看了《深入JVM》 好像没有解释

[b]问题补充:[/b]
[quote]输出为1的原因
Java语言规定:任何一个子类的构造方法都必须调用其父类的构造方法,而且调用负累构造方法的语句必须是在子类构造方法的第一条语句,其格式为:
super(调用参数列表);
“super(调用参数列表)”就会调用父类的相应构造方法。如果在程序中没有显示写上调用父类构造方法的语句,则Java在编译和执行时会在子类构造方法的第一条语句前自动地隐式地添加调用不含任何参数的父类构造方法语句。所以在调用子类的构造之前,系统会调用其父类的构造方法。因此,上述例子中输出结果第一句是“1”.
[/quote]

你没看明白我的意思。。。。。。其实 lovewhzlq 已经解释清楚了 我去查了虚拟机规范 这个应该是最小作用域的体现

朋友,问题要自动关闭啦,结分哦,

原因是:子类拥有除父类的private的方法和成员变量。
当子类的对象调用继承父类的方法时,用的是父类的对象;当调用自己的方法时,用的是自己的方法。

this代表当前方法所在的类(也就是Father类)的对象

这个设计,让继承类定义同名的私有变量[b]不会影响父类[/b],比较安全稳定。

如果父类用了私有变量,还得向别人说明子类不要再用这个变量以免出问题,是不是很囧? 私有变量和函数不就白封装隐藏了吗?

晕,DEBUG工具不过就是一个工具,语言层面规范的知识是一定的,有些东东是没法用debug工具调试的

因为你子类继承是父类,而p这个方法是从父类那继承过来的,所以对于p这个方法来说,this是代表父类的.所以是1.不信你把父类的i变量去掉肯定会报找不到变量的异常的

你写个son.q()不就明白了

[quote]
Son son = new Son();
son.p();
[/quote]
你调用 p() 返回的只可能是 “1”因为son 继承了Father类 的P()方法,如果调用了q()方法 就返回 “10”了,不知道你代码有没有写错?

Son的内存地址空间其实是有两个变量i,一个是从父类继承来的,一个是自己声明的,

千万不要以为子类变量把父类的覆盖了,

当调用父类的方法时,此时的进入的堆栈地址空间是父类的地址空间

[quote]我在Father类里写了个方法
public void s(){
System.out.println(this.getClass().getName());
}

结果为Son,证明this确实是子类的对象 [/quote]
[code="java"]
Father f = new Father();
f.s();
[/code]
打印出来的一定是 Father ,方法中this 关键字表示隐式参数,也就是被构造的对象,调用是该对象的方法和变量。

你debug模式,当进入p()方法里,把this加到Expressions里,就可以看到
"this"= Son (id=17)

i (Father)= 1

i (Son)= 10

this对象当然是代表Son ,因为只用Son son = new Son(); 新建了一个对象嘛,

因为方法是父类的,所以调用this.i得到的就是i (Father)= 1

father class
public void [u]p(){ [/u]
System.out.println(this.i);
}
son class
public void [u]q(){ [/u]
System.out.println(this.i);
}
main
son.p();
这是调用子类的方法,如果是调用的父类p()方法,输出的是1。不知道是调用子类的p()还是调用父类的q()方法?

其一,属性在对象的继承中并不存在类似于方法覆盖,首先这一点楼主要确定,如果楼主确定了这个概念,就不会有让父类方法访问到子类属性的想法了。
其二,虽然父类的属性声明了是私有的,但并不代表子类不拥有这个属性,只是子类访问不到而已,但是在父类方法中还是能访问到的,
其三,java继承中的数据结构是怎么安排的,可以去看看相关的介绍

你把那两个类的默认构造函数都写出来,就知道为什么了。
子类在初始化之前会先初始化父类,子类只不过拥有父类的一个引用super而已。
同样也拥有访问级别,
[quote]
Son的内存地址空间其实是有两个变量i,一个是从父类继承来的,一个是自己声明的,
[/quote]
太谬了

因为你调用的是父类的方法p(),如果你覆盖了父类的方法,那么输出的就是10了

[table]
||
[/table][f :cry: :oops: 8) lash=200,200][/flash][url][/url][img][/img][list]
[*] :arrow: :wink: :cry: :oops: :P
[/list][code="java"][/code][quote][/quote][u][/u][i][/i][b][/b]

[size=medium][b]输出为1的原因[/b][/size]
Java语言规定:任何一个子类的构造方法都必须调用其父类的构造方法,而且调用负累构造方法的语句必须是在子类构造方法的第一条语句,其格式为:
super(调用参数列表);
“super(调用参数列表)”就会调用父类的相应构造方法。如果在程序中没有显示写上调用父类构造方法的语句,则Java在编译和执行时会在子类构造方法的第一条语句前自动地隐式地添加调用不含任何参数的父类构造方法语句。所以在调用子类的构造之前,系统会调用其父类的构造方法。因此,上述例子中输出结果第一句是“1”.

是同名变量的屏蔽问题