博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java 多态,和方法覆盖分析(转)
阅读量:5959 次
发布时间:2019-06-19

本文共 2237 字,大约阅读时间需要 7 分钟。

多态 (Polymorphism) 大家应该都不陌生,它是我们开发面向对象系统的“老朋友”了 。但是老朋友也会有“烦心”的时候啊,呵呵。有时候 不注意,还真会被它难到。譬如下面这个例子(thank Hayden)。大家可以先不看下面的答案,在自己脑海中运行一道,看看自己想的跟实际结果是否 相符。

public class Polymorphism{
 public static void main(String[] args) {
  A b = new B();
  b.fb();
 }
}
class A {
 public A(){
  
 }
 public void fa() {
  System.out.println("CLASS A :Function fa Runing......");
 }
 public void fb() {
  System.out.println("CLASS A :Function fb Runing......");
  fa();
  System.out.println("CLASS A :Function fb Stop......");
 }
}
class B extends A {
 public B(){
 }
 public void fa() {
  System.out.println("CLASS B :Function fa Runing......");
 }
 public void fb() {
  System.out.println("CLASS B :Function fb Runing......");
  super.fb();
  System.out.println("CLASS B :Function fb Stop......");
 }
}

下面是它的运行结果:

CLASS B :Function fb Runing......
CLASS A :Function fb Runing......
CLASS B :Function fa Runing......
CLASS A :Function fb Stop......
CLASS B :Function fb Stop......

   怎么样,猜对结果了吗?如果结果跟你想象的一模一样,那么恭喜你,你对多态已经有初步了解了,起码在语法层次上是比较熟悉了。但是,千万不要“洋洋得意”,你可否解析结果为什么会是这样吗?我们可以先来梳理一下程序流程:

   1、运行main函数,创建B对象,调用B的方法fb,于是打印出"CLASS B :Function fb Runing......",都在情理之中。
   2、执行super.fb(),调用父类A的方法fb,首先打印出"CLASS A :Function fb Runing......",预料之中
   3、执行方法fa(),打印出"CLASS B :Function fa Runing......",呃?奇怪了,为什么不是执行A的方法fa(),而是子类B中的fa()呢?当前被执行的是类A的方法,那么虚拟机找到的应该是A类的Method Table,找到的应该是A类的方法fa()啊?难解~
   4、打印"CLASS A :Function fb Stop......",返回
   5、打印"CLASS A :Function fb Stop.....",返回,程序结束。
  现在问题清楚了,就是虚拟机在执行类A方法的时候查找的Method Table竟然是子类B的。为什么呢?其实,只要我们清楚java方法调用的方 式,这个问题就迎刃而解了。在Java虚拟机中,每启动一个新的线程,虚拟机都会为它分配一个Java栈,而每当线程调用一个java方法时,虚拟机就会 在该线程的java栈中压入一个新帧,用以存储参数,局部变量等数据。我们将这个正在被执行的方法称为该线程的当前方法,其相应的栈帧为当前帧。
    好了,当我们调用一个方法时,我们需要往当前帧中压入哪些参数呢?简单,方法的参数列表中不是都说得清清楚楚的吗?嗯,对于C语言来说,这个说法 是正确的,但是对于诸如C++,Java,Python等面向对象语言来说,却是不对的。大家还记得那个"this"指针吗?!不错,在Java中,所有的实例方法(Instance Method)调用的时候都会把当前对象压入当前帧中,Java虚拟机正是通过这个参数来决定当前所使用的类(通过判断该对象的类型)
    在上面的例子中,main中调用b.fb()时,压入的当前对象自然是B类对象,我们记为b。在B的fb()中调用super.fb()时,压入 的就是刚刚压入的对象,也就是b了。同样,在A的fb中调用fa()时,压入的也是b。因此,在使用 invokevirtual指令调用fa()时,找 的就是B的方法表(当前对象b的类型为B),也就执行了类B的fa了。
    这种现象在构造函数中特别常见,因为构造函数中会隐含使用调用父类的构造函数的,如果在父类的构造函数中调用了实例方法(如 A的fa),而在子 类中又覆盖了这个实例方法(如 B的fa),那么得到的结果往往不是我们所要的。因此,我们最好不要在构造函数中使用多态方法,不然,Debug会很痛苦 的:)

转http://hi.baidu.com/daping_zhang/blog/item/2bba09fa10bc489759ee90bc.html

转载地址:http://ztuax.baihongyu.com/

你可能感兴趣的文章
Enterprise Library 3.0 体验(3):使用配置文件的Validation Application Block
查看>>
程序员,请不要抢系统管理员的饭碗
查看>>
Oracle并行计算
查看>>
ftp网络服务的搭建和配置
查看>>
强化管理远程分支机构利器之coreRODC[为企业部署Windows Server 2008系列九]
查看>>
管理Windows Server Core服务器共享文件夹
查看>>
搭建MongoDB主从复制(Master-Slave)
查看>>
net类库中发送电子邮件的方法总结
查看>>
Mybatis like查询的写法
查看>>
寻找泄漏源 密封企业敏感数据
查看>>
Jigloo 开发 SWT 的入门教程
查看>>
HTML5 学习(1) -- 介绍
查看>>
SQL 必知必会·笔记<17>使用存储过程
查看>>
Linux上的SCWS安装与使用(包括PHP扩展)
查看>>
spark rdd saveAsTextFile保存为文件
查看>>
ArcGIS “Error HRESULT E_FAIL has been returned from a call to a COM component.” 异常的解决
查看>>
NeHe OpenGL教程 第十七课:2D图像文字
查看>>
.NET开源项目(转)
查看>>
补码[基础]
查看>>
两个乒乓球队进行比赛问题
查看>>