A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© yangfengxiao 中级黑马   /  2012-9-29 22:58  /  6766 人查看  /  18 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 yangfengxiao 于 2012-9-30 00:08 编辑
  1. class Fu {
  2.         int age = 40;
  3. }

  4. class Zi extends Fu {
  5.         int age = 18;
  6. }

  7. public class Test {
  8.         public static void main(String[] args) {
  9.                 Fu f = new Zi();
  10.                 System.out.println(f.age);// 结果是40,为什么?只要知道为什么创建子类对象,打印的还是父类的属性呢??
  11.                 // 我不要结论,也不要告诉我成员方法和静态方法分别是怎么调用的!!!
  12.         }

  13. }
复制代码

18 个回复

倒序浏览
本帖最后由 宫明星 于 2012-9-29 23:17 编辑

多态是父类的引用指向了自己的子类对象。
但是有前提,必须是类与类之间有关系。要么继承,要么实现(或者覆盖也行)。
在多态中成员函数的特点:
在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。
在运行时期:参阅对象所属的类中是否有调用的方法。
简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。

但是,有一种特别要注意,那就是
多态中,成员变量:
无论编译和运行,都参考左边(引用型变量所属的类)。


也就是说
Fu f = new Zi();
System.out.println(f.age);
打印的还是父类的值。


如果是函数,打印的就是子类的值了。

点评

没有回答为什么!!!  发表于 2012-9-29 23:23

评分

参与人数 1技术分 +1 收起 理由
王海宇 + 1

查看全部评分

回复 使用道具 举报
其实我认为,是 属性不算重写。父类中已经有属性了,就不调用子类属性了。。 。。

看看有没更专业的回答。。。

点评

差不多。。还是不详细为什么。。  发表于 2012-9-29 23:24
回复 使用道具 举报
本帖最后由 郑世光 于 2012-9-29 23:58 编辑

那你记住以下就行了:
当父类引用指向子类对象时,如果是调用非静态方法,此方法就按子类的运行。
如果调用的是成员变量,此变量就是父类的值。

点评

我不要记住,我要知道为什么  发表于 2012-9-29 23:24
回复 使用道具 举报
郑世光 发表于 2012-9-29 23:14
那你记住以下就行了:
当父类引用指向子类对象时,如果是调用方法,此方法就按子类的运行。
如果调用的是成 ...

我也是这样认为的
回复 使用道具 举报
一个儿子经过化妆成了父亲,但他实际上还是儿子,那么他做的事(行为)是儿子做的还是父亲做的呢?
显然还是儿子的行为
回复 使用道具 举报
郑世光 发表于 2012-9-29 23:36
一个儿子经过化妆成了父亲,但他实际上还是儿子,那么他做的事(行为)是儿子做的还是父亲做的呢?
显然还 ...

可是上面输出的是 父亲的年龄。。
回复 使用道具 举报
本帖最后由 宫明星 于 2012-9-29 23:46 编辑

java中就是这样定义的,成员变量就是打印父类。
如果你是定义多态打印成员函数的话,那就是打印子类。
多态只是对成员函数来说,成员变量不适用。

引用前面哥们的话:应该是属性不存在覆盖,再详细点就是水平达不到了。平时也没时间研究。
回复 使用道具 举报
关键在于属性是不存在覆写这个概念的,覆写只能修饰于方法,所以,子类中重新定义一个age变量和父类中的age变量没有关系
回复 使用道具 举报
  • class Fu {
  •         int age = 40;
  • }
  • class Zi extends Fu {
  •         int age = 18;
  • }
  • public class Test {
  •         public static void main(String[] args) {
  •                 Fu f = new Zi();
  •           //注意,类型的转换!这是向上类型的转换(子类---->父类),那么调用的方法是子类覆写过的方法,常量为父类的常量(常量不存在覆写哈),所以不难解释后面的40
  •                 System.out.println(f.age);// 结果是40,为什么?只要知道为什么创建子类对象,打印的还是父类的属性呢??
  •                 // 我不要结论,也不要告诉我成员方法和静态方法分别是怎么调用的!!
  •         //个人总结:成员方法时和对象相关联的,静态方法时和类先关联的的,希望可以帮到你
  •         }
  • }


回复 使用道具 举报
小儿鱼 发表于 2012-9-29 23:42
关键在于属性是不存在覆写这个概念的,覆写只能修饰于方法,所以,子类中重新定义一个age变量和父类中的age ...

可是我创建的是子类对象,不是吗~~
回复 使用道具 举报
详细原因在毕老师的视频中的day08中,超详细!!!
自己慢慢看
回复 使用道具 举报
其实子类中有两个age属性,一个是父类的,一个是子类的。

而引用是Fu f  所以就会去调用父类的属性

如果用Zi z = new Zi() 就是子类的age

评分

参与人数 1技术分 +1 黑马币 +1 收起 理由
创出一片辉煌 + 1 + 1

查看全部评分

回复 使用道具 举报
夏诗瑶 发表于 2012-9-30 00:06
其实子类中有两个age属性,一个是父类的,一个是子类的。

而引用是Fu f  所以就会去调用父类的属性

谢谢了。under。。。
回复 使用道具 举报
小弟不才,来此一讲:
    成员变量在编译的时候,查看引用型变量所属的类中是否有被调用的成员标量,如果有,编译通过.(有)没有的话..不解释了
   当编译通过了之后运行的时候也是查看引用型变量所属的类中的成员变量.
回复 使用道具 举报
Fu f=new Zi()   这句话执行的时候 , 调用了子类构造函数,在创建子类构造函数之前 不是默认有个super();么这个时候 父类的构造函数也出来了,你f.age 自然是40了   。顺便说一句   java中的非static成员方法是 virtual的,而 非static成员变量是 非virtual的。     这类似c++的虚方法。所以  如果你要说 加入父类中有个run方法,子类去复写父类中的run方法的话,java会自动去判断是否是 virtual的 ,是,就执行子类的,不是就执行父类的。

评分

参与人数 1技术分 +1 收起 理由
王海宇 + 1

查看全部评分

回复 使用道具 举报
再多嘴一句,只学过java的人  对这个是不好理解的,所以初学的java程序员 都有点搞晕, 但是如果是C#或者C++的程序员  对这个是很好理解的。因为他们程序里面本身就有virtual
回复 使用道具 举报
我再举个 变量 和方法的例子    还是上面的 代码     Fu  f=new Zi() ,如果我这里是
f.age-----父类的
((Zi)f).age ----子类的
主要是看类型

关于java中的变量的   其实根本就是不存在多态的。   

你们说 要是java要是也有 virtual 关键字 不就好了么,这个问题解释就没这么复杂了,   有virtual修饰的才是多态(所以方法可以被virtual修饰,java默认非static方法全部被 virtual修饰了),没有被virtual修饰的 不是多态, (所以变量是不能被virtual修饰的)
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马