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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 周玉龙 中级黑马   /  2012-7-17 11:22  /  1814 人查看  /  7 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 周玉龙 于 2012-7-17 22:20 编辑

这是我们老师以前举得一个例子。

孔子爹:讲课(java)
孔子:讲课(论语),看小说
多态:
孔子爹 k = new 孔子();//向上转型 穿上他爹的衣服,带上眼镜,拿了一本java书。
k.讲课();//论语

孔子 kk = (孔子)k; //向下转型 回来后,脱下了外套,取掉眼镜,放下书
kk.讲课();//论语

class A {
  void fun1() {
    System.out.println(fun2());
  }
  int fun2() {
    return 123;
  }
}
class B extends A {
  int fun2() {
    return 456;
  }
  public static void main(String argv[]) {
    A a;
    B b = new B();
b.fun1();//子类对象调用父类的方法fun1(),但是不应该是父类的fun1()方法调用的父类fun2()方法么?
           //子类拥有父类的方法不就是可以调用它吗?还是说就是把他的方法复制过来是一个效果?
    a = b;//
a.fun1();//其实这个等价于上面的那个,
  }
}

评分

参与人数 1技术分 +1 收起 理由
韦念欣 + 1 赞一个!

查看全部评分

7 个回复

倒序浏览
别晕! 给个更恰当的比喻给你!
比如你是战场司令官,你指挥士兵开枪。在JAVA里你调用士兵开枪功能,是不是得一个一个叫?那多麻烦吖?

但是引用了多态,你就可以一句话就指挥一批士兵调用开枪功能!这就是多态的作用!

回复 使用道具 举报
class A {
  void fun1() {
    System.out.println(fun2());
  }
  int fun2() {
    return 123;
  }
}
class B extends A {
  int fun2() {
    return 456;
  }
  public static void main(String argv[]) {
    A a;
    B b = new B();
b.fun1();//既然b是a的子类,那么fun1,fun2方法也是b的方法,fun2被覆盖了,所以就会调用子类的那个fun2方法。         
            //只要子类未覆盖父类的相应地方法,子类就相当于复制过来了子类的方法了。   
  a = b;//
   a.fun1();//这里在你这种情况下是等价的 ,如果调用一个子类有但父类没有的方法,这里就会抱错了,而上边的那个就不会。
}
}
在用多态的时候是父类的引用指向了子类的对象,这个父类的引用只能调用父类已有的方法,不能调用子类有但父类没有的方法,如果子类把方法覆盖了,那么就会调用被覆盖后的那个方法。

评分

参与人数 1技术分 +1 收起 理由
韦念欣 + 1 赞一个!

查看全部评分

回复 使用道具 举报
b.fun1();//就是把他的方法复制过来是一个效果  

至于a.fun1();
相当于 B b=new  B();  ----->a=b;   -------->a=new B(); -------->A  a=new B();
A  a=new B();
表示定义了一个A类型的引用,指向新建的B类型的对象。
由于B是继承自它的父类A ,所以A类型的引用是可以指向B类型的对象。
既是在堆内存中 对象变量是a,在栈内存中new 的是B ,a对象指向了new B()
所以 a.fun1() 调用的就是B中的方法
因为是父类的引用,所以只能找到父类中的方法,或者子类中重写(覆盖)了的父类的方法。

评分

参与人数 1技术分 +1 收起 理由
韦念欣 + 1 赞一个!

查看全部评分

回复 使用道具 举报
子类对象调用父类的方法fun1(),但是不应该是父类的fun1()方法调用的父类fun2()方法么?
不是,因为子类有自己fun2()
回复 使用道具 举报
这个问题考察的是对继承的理解。
子类可直接访问父类中的非私有的属性和行为。子类默认含有父类的非私有成员,可直接调用。
理解了这一点,你的疑问就可以解答了。
b.fun1();
当子类对象b调用fun1()时,先检查自己有没有此方法,如果没有就直接调用父类的public的fun1()方法
当执行fun1()方法时,又碰到了fun2()方法,由于调用fun1()的对象是子类对象b,那么自然还是在b中查找有没有方法fun2(),这里b有自己重写的fun2(),那么将调用b自己的fun2()。

a=b;
a.fun1();
至于父类对象a调用fun1(),这里出现了多态,父类引用a指向了子类对象b(即new B()),那么在执行a.fun1()时,就要分编译时和运行时来进行分析。
编译时,检查引用型变量所属的类(即对象a所属的类A)中是否有fun1()方法,这里类A中存在方法fun1(),编译通过
运行时,检查对象所属的类(即对象b所属的类B)中是否有fun1()方法,这里由于类B是类A的子类,继承了A的fun1()方法,所以类B中也存在方法fun1(),能够正确运行。


评分

参与人数 1技术分 +1 收起 理由
韦念欣 + 1 赞一个!

查看全部评分

回复 使用道具 举报
王达 发表于 2012-7-17 11:38
class A {
  void fun1() {
    System.out.println(fun2());

哦,明白了。谢谢。
回复 使用道具 举报
周坤 中级黑马 2012-7-17 12:02:39
8#
多态成员运行的特点:Fu f=new Zi();
在编译时期,参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有,编译失败。
在运行时期,参阅对象所属的类中是否有调用的方法。
简单总结就是成员函数在多态调用时,编译看左边,运行看右边。
在多态中,成员变量的特点,无论编译和运行时,都参考左边(引用型变量所属的类);
在多态中,对于静态函数来讲,
无论编译和运行,都参考左边。
静态方法static静态绑定的是类,非静态成员方法动态绑定,绑定的是对象。静态变量也如是。
即静态绑定即绑定类,随着类的建立而加载,
动态绑定即绑定对象,随着对象的建立而加载。

其中,class B中fun2方法覆盖了class A中的方法,所以执行b.fun1();的时候,要先继承父类的fun1();放发现子类重写了父类fun2(),则子类将不调用父类的fun2();而是调用自己的方法,这个是继承的过程,不涉及多态。
而第二个则是多态,但要知道多态自始至终都是子类对象在做变化。这里a.fun1()在实现上和b.fun1()是一样的,但a始终是父类的引用,现在指向了子类的对象,属于多态机制。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马