父类引用指向子类对象的问题

中微子 2012-06-13 11:15:24
FatherClass f = new SonClass()


当父类引用f指向其子类的对象的时候,通过f无法访问专属于子类对象的成员。

假如子类中有对父类方法的重写,那么根据多态机制,通过f访问这个方法的时候实际访问的是子类中重写的方法。

问题是如果子类重写的方法中访问了专属于子类的成员变量,这时候通过父类引用f还可以调用那个被重写的方法吗?
...全文
3180 51 打赏 收藏 转发到动态 举报
写回复
用AI写文章
51 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq_25134377 2015-01-07
  • 打赏
  • 举报
回复
引用 7 楼 qybao 的回复:
当父类引用f指向其子类的对象的时候,通过f无法访问专属于子类对象的成员。 为什么这样不可以?LZ有没有想过,因为f是FatherClass,所以编译器只知道f拥有FatherClass.class的信息,FatherClass.class以外的信息,编译器不知道,而子类的对象成员是在SonClass.class里,也就是说在FatherClass.class以外,所以f无法访问子类的对象成员 假如子类中有对父类方法的重写,那么根据多态机制,通过f访问这个方法的时候实际访问的是子类中重写的方法。 为什么这样可以?上面说了,f只能访问FatherClass.class的信息(注意这里指的是编译期编译器只知道f是FatherClass类型,不知道f具体指向什么对象,运行期才知道指向什么对象),而子类重写的方法,父类中也存在,即SonClass.class重写的方法,FatherClass.class里也有(如果SonClass.class里有但是FatherClass.class里没有的方法,f也不能直接调用),所以f可以访问,但是调用的时候(注意这里指的是运行期),f实际指向的是SonClass对象,所以调用的是SonClass对象的方法。 问题是如果子类重写的方法中访问了专属于子类的成员变量,这时候通过父类引用f还可以调用那个被重写的方法吗? 可以,要分清编译期和运行期,编译期是编译器检查语法和类型,运行期是解析器解析伪代码为机器指令而执行,编译期编译器会检查f的访问范围,也就是f的访问不超过FatherClass.class的信息就不会出错,运行期解析器会解析方法的代码指令,因为f指向子类对象,所以会解析子类重写的方法代码指令,而子类对象的内存空间是包含子类的成员变量的空间的,所以也不存在子类成员变量没有分配内存的问题,所以可以调用。 LZ要分清楚,为什么会生成FatherClass.class和SonClass.class两个文件,既然是生成两个文件,那当然是那个文件被使用,就可以访问那个文件的信息。编译期编译器只知道f是FatherClass类型(至于f=什么,那是运行期,因为不运行=就不会执行),所以会检查f是否在FatherClass.class的范围,而运行期,f指向的是SonClass对象,也就是内存的对象是SonClass.class的信息,所以执行的是SonClass.class的代码指令。
七楼,为我解释了,为什么在运行期父类的引用可以调用子类中重写了父类方法的方法。现在我又不理解了,那么在运行期,为什么父类的引用可以调用父类中自己的方法,按理说这个时候父类的引用它的类型已经被知道了,为什么还能调用父类的方法?
免费范文 2013-11-13
  • 打赏
  • 举报
回复
明白了 就是老子叫儿子过来做 老子教会儿子做的事情,至于儿子会做什么别的事和怎么做都不管。
mouttz 2013-10-01
  • 打赏
  • 举报
回复
引用 48 楼 mouttz 的回复:
[quote=引用 7 楼 qybao 的回复:] 当父类引用f指向其子类的对象的时候,通过f无法访问专属于子类对象的成员。 为什么这样不可以?LZ有没有想过,因为f是FatherClass,所以编译器只知道f拥有FatherClass.class的信息,FatherClass.class以外的信息,编译器不知道,而子类的对象成员是在SonClass.class里,也就是说在FatherClass.class以外,所以f无法访问子类的对象成员 假如子类中有对父类方法的重写,那么根据多态机制,通过f访问这个方法的时候实际访问的是子类中重写的方法。 为什么这样可以?上面说了,f只能访问FatherClass.class的信息(注意这里指的是编译期编译器只知道f是FatherClass类型,不知道f具体指向什么对象,运行期才知道指向什么对象),而子类重写的方法,父类中也存在,即SonClass.class重写的方法,FatherClass.class里也有(如果SonClass.class里有但是FatherClass.class里没有的方法,f也不能直接调用),所以f可以访问,但是调用的时候(注意这里指的是运行期),f实际指向的是SonClass对象,所以调用的是SonClass对象的方法。 问题是如果子类重写的方法中访问了专属于子类的成员变量,这时候通过父类引用f还可以调用那个被重写的方法吗? 可以,要分清编译期和运行期,编译期是编译器检查语法和类型,运行期是解析器解析伪代码为机器指令而执行,编译期编译器会检查f的访问范围,也就是f的访问不超过FatherClass.class的信息就不会出错,运行期解析器会解析方法的代码指令,因为f指向子类对象,所以会解析子类重写的方法代码指令,而子类对象的内存空间是包含子类的成员变量的空间的,所以也不存在子类成员变量没有分配内存的问题,所以可以调用。 LZ要分清楚,为什么会生成FatherClass.class和SonClass.class两个文件,既然是生成两个文件,那当然是那个文件被使用,就可以访问那个文件的信息。编译期编译器只知道f是FatherClass类型(至于f=什么,那是运行期,因为不运行=就不会执行),所以会检查f是否在FatherClass.class的范围,而运行期,f指向的是SonClass对象,也就是内存的对象是SonClass.class的信息,所以执行的是SonClass.class的代码指令。
为什么会生成FatherClass.class和SonClass.class两个文件,貌似只要有这个类存在就会生成字节码[/quote]误会你的意思了,所以父类引用编译时检测有效范围,运行时指向子类对象,两个条件决定它不能访问除了父类中已有的子类方法。
mouttz 2013-10-01
  • 打赏
  • 举报
回复
引用 7 楼 qybao 的回复:
当父类引用f指向其子类的对象的时候,通过f无法访问专属于子类对象的成员。 为什么这样不可以?LZ有没有想过,因为f是FatherClass,所以编译器只知道f拥有FatherClass.class的信息,FatherClass.class以外的信息,编译器不知道,而子类的对象成员是在SonClass.class里,也就是说在FatherClass.class以外,所以f无法访问子类的对象成员 假如子类中有对父类方法的重写,那么根据多态机制,通过f访问这个方法的时候实际访问的是子类中重写的方法。 为什么这样可以?上面说了,f只能访问FatherClass.class的信息(注意这里指的是编译期编译器只知道f是FatherClass类型,不知道f具体指向什么对象,运行期才知道指向什么对象),而子类重写的方法,父类中也存在,即SonClass.class重写的方法,FatherClass.class里也有(如果SonClass.class里有但是FatherClass.class里没有的方法,f也不能直接调用),所以f可以访问,但是调用的时候(注意这里指的是运行期),f实际指向的是SonClass对象,所以调用的是SonClass对象的方法。 问题是如果子类重写的方法中访问了专属于子类的成员变量,这时候通过父类引用f还可以调用那个被重写的方法吗? 可以,要分清编译期和运行期,编译期是编译器检查语法和类型,运行期是解析器解析伪代码为机器指令而执行,编译期编译器会检查f的访问范围,也就是f的访问不超过FatherClass.class的信息就不会出错,运行期解析器会解析方法的代码指令,因为f指向子类对象,所以会解析子类重写的方法代码指令,而子类对象的内存空间是包含子类的成员变量的空间的,所以也不存在子类成员变量没有分配内存的问题,所以可以调用。 LZ要分清楚,为什么会生成FatherClass.class和SonClass.class两个文件,既然是生成两个文件,那当然是那个文件被使用,就可以访问那个文件的信息。编译期编译器只知道f是FatherClass类型(至于f=什么,那是运行期,因为不运行=就不会执行),所以会检查f是否在FatherClass.class的范围,而运行期,f指向的是SonClass对象,也就是内存的对象是SonClass.class的信息,所以执行的是SonClass.class的代码指令。
为什么会生成FatherClass.class和SonClass.class两个文件,貌似只要有这个类存在就会生成字节码
KingZhCool 2013-05-28
  • 打赏
  • 举报
回复
package com.zhou; public class DuoTai { public static void main(String[] args) { A a = new B(); // a.tell(); // // A a = new A(); B b = (B)a; // a.tell(); b.run(); } } class A{ public void tell(){ System.out.println("我是父类!"); } } class B extends A{ String s = "我是子类!"; public void tell(){ System.out.println(s); } public void run(){ System.out.println("奔跑!"); } }
MartinCorner 2013-04-08
  • 打赏
  • 举报
回复
有大神答疑解惑就是效率高啊
LS1firesoar 2012-11-02
  • 打赏
  • 举报
回复
可以的,你FatherClass f = new SonClass()


虽然表面上看是FatherClass ,其实本质是SonClass
jvm会自己知道的,虽然你不能f.sonMethod(),这样会无法编译。
但是f.fatherMethod()其实是调用sonClass.sonMthod。所以没关系,本质是son
changtianshuiyue 2012-11-02
  • 打赏
  • 举报
回复
光死记规则没用的,得想想为什么,还是运行和编译的问题。
牛角突围录 2012-10-31
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 的回复:]

编译看左边,运行看右边,
[/Quote]

可以的
KelvenCheung 2012-10-29
  • 打赏
  • 举报
回复
看完回复,没什么好补充
ewth126 2012-10-28
  • 打赏
  • 举报
回复
35楼这句话说得好。
最后执行的结果是,哪个类的对象传递给父类,就调用哪个类的方法。

但是那个是动态绑定。不是多态绑定吧。
print_er 2012-10-28
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 的回复:]
当父类引用f指向其子类的对象的时候,通过f无法访问专属于子类对象的成员。
为什么这样不可以?LZ有没有想过,因为f是FatherClass,所以编译器只知道f拥有FatherClass.class的信息,FatherClass.class以外的信息,编译器不知道,而子类的对象成员是在SonClass.class里,也就是说在FatherClass.class以外,所以f无法访问子类的对象成员
……
[/Quote]
+++++++
学习了
IT0918liu 2012-10-28
  • 打赏
  • 举报
回复
这个帖子不错,七楼大牛
一起来玩玩呗 2012-10-28
  • 打赏
  • 举报
回复
修改下测试类中的代码是:A a = new B(); a.print();
一起来玩玩呗 2012-10-28
  • 打赏
  • 举报
回复
class A {
public void print(){
System.out.println("A");
}
}
class B extends A {
private int a = 0;
public void print(){
System.out.println(a);
}
}
public class _Test {
public static void main(String[] args){
new B().print();
}
}

多态的三个条件:继承,重写,父类引用指向子类对象。
七楼说的很好,我总结了下:
多态有两种一是:编译时的多态,编译时的多态一般表现为方法的重载,一个类中存在多个相同名字的方法,但方法的参数不用(方法的数据类型等),在编译时,根据方法传递过来的实参进行重载。
二是:运行时的多态,也叫做多态绑定。子类重写父类的方法后。把子类的引用传递给父类对象,然后通过父类的对象去调用子类覆盖的方法。最后执行的结果是,哪个类的对象传递给父类,就调用哪个类的方法。
yahier 2012-10-28
  • 打赏
  • 举报
回复
就算子类重写了父类的方法,它仍然是调用父类的 所以。。
zzssjava 2012-10-25
  • 打赏
  • 举报
回复
受益匪浅啊。厉害。哈哈。感觉突然一下子顿悟了很多东西
jasshine 2012-10-24
  • 打赏
  • 举报
回复
看了7楼的解释,瞬间不想自己的解释了
w2zysys 2012-07-27
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 的回复:]
可以的,你可以看下我写的这个例子:

Java code


class Animal {
public void eat(){
System.out.println("Animal Eating...");
}
public void sleep() {
System.out.println("Animal Sleeping...");
}
……
[/Quote]

没有继承
VanBaston 2012-07-27
  • 打赏
  • 举报
回复
其实简单的一点的想,如果子类重写的父类方法,不能处理子类里一些自己的属性内容,那个我们所谓的多态还有意义没呢?而且这样的话我们继承重写的时候是不是回要设定一个规则,就是重写的方法还要限制不能使用子类特有的属性和方法呢?
如果这样的话,继承,重写,动态绑定还有什么意思呢?
加载更多回复(28)

62,636

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧