知识大全 理解java的多形性
Posted 类型
篇首语:读和写是学生最必要的两种学习方法,也是通向周围世界的两扇窗口。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 理解java的多形性相关的知识,希望对你有一定的参考价值。
对于面向对象的程序设计语言 多型性是第三种最基本的特征(前两种是数据抽象和继承 多形性 (Polymorphism)从另一个角度将接口从具体的实施细节中分离出来 亦即实现了 是什么 与 怎样做 两个模块的分离 利用多形性的概念 代码的组织以及可读性均能获得改善 此外 还能创建 易于扩展 的程序 无论在项目的创建过程中 还是在需要加入新特性的时候 它们都可以方便地 成长 通过合并各种特征与行为 封装技术可创建出新的数据类型 通过对具体实施细节的隐藏 可将接口与实施细节分离 使所有细节成为 private (私有) 这种组织方式使那些有程序化编程背景人感觉颇为舒适 但多形性却涉及对 类型 的分解 通过上一章的学习 大家已知道通过继承可将一个对象当作它自己的类型或者它自己的基础类型对待 这种能力是十分重要的 因为多个类型(从相同的基础类型中衍生出来)可被当作同一种类型对待 而且只需一段代码 即可对所有不同的类型进行同样的处理 利用具有多形性的方法调用 一种类型可将自己与另一种相似的类型区分开 只要它们都是从相同的基础类型中衍生出来的 这种区分是通过各种方法在行为上的差异实现的 可通过基础类实现对那些方法的调用 在这一章中 大家要由浅入深地学习有关多形性的问题(也叫作动态绑定 推迟绑定或者运行期绑定) 同时举一些简单的例子 其中所有无关的部分都已剥除 只保留与多形性有关的代码 上溯造型 在第 章 大家已知道可将一个对象作为它自己的类型使用 或者作为它的基础类型的一个对象使用 取得一个对象句柄 并将其作为基础类型句柄使用的行为就叫作 上溯造型 ——因为继承树的画法是基础类位于最上方 但这样做也会遇到一个问题 如下例所示(若执行这个程序遇到麻烦 请参考第 章的 小节 赋值 ) //: Music java // Inheritance & upcasting package c ; class Note private int value; private Note(int val) value = val; public static final Note middleC = new Note( ) cSharp = new Note( ) cFlat = new Note( ); // Etc class Instrument public void play(Note n) System out println( Instrument play() ); // Wind objects are instruments // because they have the same interface: class Wind extends Instrument // Redefine interface method: public void play(Note n) System out println( Wind play() ); public class Music public static void tune(Instrument i) // i play(Note middleC); public static void main(String[] args) Wind flute = new Wind(); tune(flute); // Upcasting ///:~ 其中 方法Music tune()接收一个Instrument句柄 同时也接收从Instrument衍生出来的所有东西 当一个Wind句柄传递给tune()的时候 就会出现这种情况 此时没有造型的必要 这样做是可以接受的 Instrument里的接口必须存在于Wind中 因为Wind是从Instrument里继承得到的 从Wind向Instrument的上溯造型可能 缩小 那个接口 但不可能把它变得比Instrument的完整接口还要小 为什么要上溯造型 这个程序看起来也许显得有些奇怪 为什么所有人都应该有意忘记一个对象的类型呢?进行上溯造型时 就可能产生这方面的疑惑 而且如果让tune()简单地取得一个Wind句柄 将其作为自己的自变量使用 似乎会更加简单 直观得多 但要注意 假如那样做 就需为系统内Instrument的每种类型写一个全新的tune() 假设按照前面的推论 加入Stringed(弦乐)和Brass(铜管)这两种Instrument(乐器) //: Music java // Overloading instead of upcasting class Note private int value; private Note (int val) value = val; public static final Note middleC = new Note ( ) cSharp = new Note ( ) cFlat = new Note ( ); // Etc class Instrument public void play(Note n) System out println( Instrument play() ); class Wind extends Instrument public void play(Note n) System out println( Wind play() ); class Stringed extends Instrument public void play(Note n) System out println( Stringed play() ); class Brass extends Instrument public void play(Note n) System out println( Brass play() ); public class Music public static void tune(Wind i) i play(Note middleC); public static void tune(Stringed i) i play(Note middleC); public static void tune(Brass i) i play(Note middleC); public static void main(String[] args) Wind flute = new Wind (); Stringed violin = new Stringed (); Brass frenchHorn = new Brass (); tune(flute); // No upcasting tune(violin); tune(frenchHorn); ///:~ 这样做当然行得通 但却存在一个极大的弊端 必须为每种新增的Instrument 类编写与类紧密相关的方法 这意味着第一次就要求多得多的编程量 以后 假如想添加一个象tune()那样的新方法或者为Instrument添加一个新类型 仍然需要进行大量编码工作 此外 即使忘记对自己的某个方法进行过载设置 编译器也不会提示任何错误 这样一来 类型的整个操作过程就显得极难管理 有失控的危险 但假如只写一个方法 将基础类作为自变量或参数使用 而不是使用那些特定的衍生类 岂不是会简单得多?也就是说 如果我们能不顾衍生类 只让自己的代码与基础类打交道 那么省下的工作量将是难以估计的 这正是 多形性 大显身手的地方 然而 大多数程序员(特别是有程序化编程背景的)对于多形性的工作原理仍然显得有些生疏 深入理解 对于Music java的困难性 可通过运行程序加以体会 输出是Wind play() 这当然是我们希望的输出 但它看起来似乎并不愿按我们的希望行事 请观察一下tune()方法 public static void tune(Instrument i) // i play(Note middleC); 它接收Instrument句柄 所以在这种情况下 编译器怎样才能知道Instrument句柄指向的是一个Wind 而不是一个Brass或Stringed呢?编译器无从得知 为了深入了理解这个问题 我们有必要探讨一下 绑定 这个主题 方法调用的绑定 将一个方法调用同一个方法主体连接到一起就称为 绑定 (Binding) 若在程序运行以前执行绑定(由编译器和链接程序 如果有的话) 就叫作 早期绑定 大家以前或许从未听说过这个术语 因为它在任何程序化语言里都是不可能的 C编译器只有一种方法调用 那就是 早期绑定 上述程序最令人迷惑不解的地方全与早期绑定有关 因为在只有一个Instrument句柄的前提下 编译器不知道具体该调用哪个方法 解决的方法就是 后期绑定 它意味着绑定在运行期间进行 以对象的类型为基础 后期绑定也叫作 动态绑定 或 运行期绑定 若一种语言实现了后期绑定 同时必须提供一些机制 可在运行期间判断对象的类型 并分别调用适当的方法 也就是说 编译器此时依然不知道对象的类型 但方法调用机制能自己去调查 找到正确的方法主体 不同的语言对后期绑定的实现方法是有所区别的 但我们至少可以这样认为 它们都要在对象中安插某些特殊类型的信息 Java中绑定的所有方法都采用后期绑定技术 除非一个方法已被声明成final 这意味着我们通常不必决定是否应进行后期绑定——它是自动发生的 为什么要把一个方法声明成final呢?正如上一章指出的那样 它能防止其他人覆蓋那个方法 但也许更重要的一点是 它可有效地 关闭 动态绑定 或者告诉编译器不需要进行动态绑定 这样一来 编译器就可为final方法调用生成效率更高的代码 产生正确的行为 知道Java里绑定的所有方法都通过后期绑定具有多形性以后 就可以相应地编写自己的代码 令其与基础类沟通 此时 所有的衍生类都保证能用相同的代码正常地工作 或者换用另一种方法 我们可以 将一条消息发给一个对象 让对象自行判断要做什么事情 在面向对象的程序设计中 有一个经典的 形状 例子 由于它很容易用可视化的形式表现出来 所以经常都用它说明问题 但很不幸的是 它可能误导初学者认为OOP只是为图形化编程设计的 这种认识当然是错误的 cha138/Article/program/Java/JSP/201311/19669相关参考
《深入理解Java虚拟机》笔记 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 在C里面我们想
<%@pagecontentType=text/charset=utfpageEncoding=GBK%> jsp页面(pageEncoding)——根据pageEncoding的设
知识大全 如何理解平台这个概念 如windows平台,linux平台,java平台
如何理解平台这个概念如windows平台,linux平台,java平台可以理解为环境即能使程序运行的软硬件环境如何将非JAVA平台变成JAVA平台?(手机的)那属于硬件问题,改不掉的,就像初期的mtk
JAVA编程解析之classpath的深入理解 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 现
Java基本功之中断线程的理解 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 设想这样的情景我们
(一)相关类 (二)问题以下输出结果是什么? (
知识大全 深入理解Java Servlet与Web容器之间的关系
深入理解JavaServlet与Web容器之间的关系 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
上一次在使用Java开始面向对象的编程这篇文章中我们学习了一个编程语言要真正成为面向对象的它应该支持信息隐藏/封装多态继承和动态绑定另外我们知道了Java完全支持这些功能而且知道了因为Java是一
JAVA的设计模式我想大家都知道但每个人的理解并不相同我在这里只是阐述我的观点要是与您的观点不同请您原谅和提出您的宝贵意见 为了把命令模式讲清楚我要举一个大家都影象深刻的例子以便大家的理解那
通过依赖注入来从不同的部门获取数据借助其来理解Spring的IOC [java] packagexliocdemo; publicinterfaceDataManagement //使用该