java运行时多态性的实现

运行时多态性是面向对象程序设计代码重用的一个最强大机制,动态性的概念也可以被说成“一个接口,多个方法”。Java实现运行时多态性的基础是动态方法调度,它是一种在运行时而不是在编译期调用重载方法的机制,下面就继承和接口实现两方面谈谈java运行时多态性的实现。

一、通过继承中超类对象引用变量引用子类对象来实现

举例说明:

//定义超类superA

class superA

{

int i = 100;

void fun()

{

System.out.println(“This is superA”);

}

}

//定义superA的子类subB

class subB extends superA

{

int m = 1;

void fun()

{

System.out.println(“This is subB”);

}

}

//定义superA的子类subC

class subC extends superA

{

int n = 1;

void fun()

{

System.out.println(“This is subC”);

}

}

class Test

{

public static void main(String[] args)

{

superA a;

subB b = new subB();

subC c = new subC();

a=b;

a.fun(); (1)

a=c;

a.fun(); (2)

}

}

运行结果为:

This is subB

This is subC

上述代码中subB和subC是超类superA的子类,我们在类Test中声明了3个引用变量a, b, c,通过将子类对象引用赋值给超类对象引用变量来实现动态方法调用。也许有人会问:“为什么(1)和(2)不输出:This is superA”。java 的这种机制遵循一个原则:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。

所以,不要被上例中(1)和(2)所迷惑,虽然写成a.fun(),但是由于(1)中的a被b赋值,指向了子类subB的一个实例,因而(1)所调用的fun()实际上是子类subB的成员方法fun(),它覆盖了超类superA的成员方法fun();同样(2)调用的是子类subC的成员方法fun()。

另外,如果子类继承的超类是一个抽象类,虽然抽象类不能通过new操作符实例化,但是可以创建抽象类的对象引用指向子类对象,以实现运行时多态性。具体的实现方法同上例。

不过,抽象类的子类必须覆盖实现超类中的所有的抽象方法,否则子类必须被abstract修饰符修饰,当然也就不能被实例化了。

二、通过接口类型变量引用实现接口的类的对象来实现

接口的灵活性就在于“规定一个类必须做什么,而不管你如何做”。我们可以定义一个接口类型的引用变量来引用实现接口的类的实例,当这个引用调用方法时,它会根据实际引用的类的实例来判断具体调用哪个方法,这和上述的超类对象引用访问子类对象的机制相似。

举例说明:

//定义接口InterA

interface InterA

{

void fun();

}

//实现接口InterA的类B

class B implements InterA

{

public void fun()

{

System.out.println(“This is B”);

}

}

//实现接口InterA的类C

class C implements InterA

{

public void fun()

{

System.out.println(“This is C”);

}

}

class Test

{

public static void main(String[] args)

{

InterA a;

a= new B();

a.fun();

a = new C();

a.fun();

}

}

输出结果为:

This is B

This is C

上例中类B和类C是实现接口InterA的两个类,分别实现了接口的方法fun(),通过将类B和类C的实例赋给接口引用a而实现了方法在运行时的动态绑定,充分利用了“一个接口,多个方法”展示了Java的动态多态性。

需要注意的一点是:Java在利用接口变量调用其实现类的对象的方法时,该方法必须已经在接口中被声明,而且在接口的实现类中该实现方法的类型和参数必须与接口中所定义的精确匹配。

结束语:以上就是java运行时多态性的实现方法,大家在编程过程中可以灵活运用,但是在性能要求较高的代码中不提倡运用运行时多态,毕竟Java的运行时动态方法调用较之普通的方法调用的系统开销是比较大的。

时间: 2024-10-05 20:08:48

java运行时多态性的实现的相关文章

将子类对象引用赋值给超类对象 JAVA 编译时多态性

将子类对象引用赋值给超类对象 JAVA 编译时多态性(转) (2012-05-10 11:24:05) 转载▼ 标签: 杂谈 分类: 也无晴_soft 1.通过将子类对象引用赋值给超类对象引用变量来实现动态方法调用. DerivedC c2=new DerivedC(); BaseClass a1= c2; //BaseClass 基类,DerivedC是继承自BaseClass的子类 a1.play(); //play()在BaseClass,DerivedC中均有定义,即子类覆写了该方法 分

深入理解java虚拟机一 JAVA运行时内存区域与class文件

一 JAVA运行时内存区域 JVM在加载class文件时,会将class文件定义的数据结构转为运行时内存中的数据,那么jvm是如何安排运行时的内存区域呢? jvm将运行时内存划分为以下几个部分: 堆:所有线程共享 方法区:类信息.静态变量.常量等 运行时常量池:class文件的常量池(字面常量和符号引用)+运行时产生的常量 程序计数器:  当前线程执行的字节码的行号指示器 虚拟机栈:栈帧 = 本地局部变量表.操作数栈.动态链接.出口信息 本地方法栈:native方法 直接内存:不属于jvm管理,

Jvm基础-Java运行时数据区

最近在看<深入理解Java虚拟机>,里面讲到了Java运行时数据区,这是Jvm基本知识,把读书笔记记录在此.这些知识属于常识,都能查到的,如果我有理解不对的地方,还请指出. 首先把图贴上来,图来自JVM Runtime Data Areas(运行时数据区),感谢. 由上图可知,Java运行时数据区域包括程序计数器.Java虚拟机栈.本地方法栈.Java堆.方法区. 1. 程序计数器 程序计数器用来记录下一条字节码指令,因为CPU是要轮转的,在切换回来之后,Java能够找到下一条要执行的指令.如

java运行时内存模式学习

学习java运行时内存模式: 各区介绍: 方法区(线程共享):用于存放被虚拟机加载的类的元数据:静态变量,常量,以及编译和的代码(字节码),也称为永久代(所有该类的实例被回收,或者此类classLoader被回收). Java堆(线程共享):存放对象实例和数组,这里是内存回收的主要地方.可以分为新生代(young)和年老代(tenured).从字面也可以知道,新生代存放刚刚建立的对象 而年老代存放长久没有被垃圾回收机制回收的对象.一般新生代有分为eden,from survivor和to sur

深入理解Java运行时数据区

前情回顾 在本专栏的前12篇博客中, 我们主要大致介绍了什么是JVM, 并且详细介绍了class文件的格式. 对于深入理解Java, 或者深入理解运行于JVM上的其他语言, 深入理解class文件格式都是必须的. 如果读者对class文件的格式不是很熟悉, 在阅读本博客下面的文章之前, 建议先读一下前面的12篇博客, 或者参考其他资料, 熟悉class文件的格式. 在深入理解Java虚拟机到底是什么 这篇博客中, 我们有提到过, JVM就是一个特殊的进程, 我们执行的java程序, 都运行在一个

Java运行时数据区域划分

Java运行时数据区域划分 Java JVM 内存 堆 栈 1. 概述 对于Java程序员来说,在虚拟机自动内存管理机制下,不容易出现内存泄漏和内存溢出现象.但如果不了解虚拟机是如何使用内存的,一旦出现了内存泄漏和溢出方面的问题,那么排错就无从下手了. 2. 运行时数据区域 Java虚拟机在执行Java程序的过程中会将它所管理的内存划分为若干个不同的数据区域,如下图所示. 2.1. 程序计数器 程序计数器(Program Counter Register):是一块较小的内存空间,可以看做是当前线

Java运行时数据区

Java虚拟机定义了一些程序运行期间会使用到的数据区域,其中一些会随着JVM的启动而创建,随着JVM的退出而销毁:另外一些则与线程的运行一一对立的,这些数据区域会随着线程的开始而创建,随着线程的结束而销毁.下面是一张Java运行时的数据区模型图: 总的来说,Java运行时数据区域可以分为两个部分:线程共享的区域和线程独享的区域.下面一一对之进行总结. 一.线程共享区域:线程共享区域是指各个线程都会使用到的一块空间区域,它们会在这里申请空间.使用空间.根据具体提供功能不同,可以划分为两个部分,分别

Java运行时环境JPEGImageWriter.writeImage函数整数溢出漏洞_

在使用PDFBOX的接口,代码如下: PDFImageWriter imageWriter = new PDFImageWriter(); imageWriter.writeImage(pdDoc, imageType, null, startPage, endPage, imageFilePath, 1, Constants.NUM_TWO_HUNDRED),发现图片生成了,但是报内存溢出错误.后面看了下源代码搜寻相关资料发现存在这样一个问题,所以更换JDK就OK了. Java运行时环境的JP

Java运行时内存

对于java程序员来说,并不必显示地对内存进行管理,一切都交给java虚拟机去做吧,而且,你也不一定做得比java虚拟机来得专业.好像所有内存管理都交给虚拟机去做就万事大吉了,但是,事实有时并非如此,可能有时你会遇到一些让你困惑的问题,如OutOfMemoryError异常,如stackOverflowError,你开始大呼,虚拟机不是都为我们管理好内存了吗?怎么还会出现这样的Error,其实当你真正去了解java虚拟机内存区域的分布的时候,你就会不自觉的大呼:原来java虚拟机也不是万能. 这