`

第八章 多态

阅读更多
2013年6月17日 星期一 23时34分54秒

第八章 多态
        在面向对象的程序设计语言中,多态是继续数据抽象和继承之后的第三种基本特征。
        多态通过分离做什么和怎么做,从另一角度讲接口和实现分离开来。
        ”封装“是通过合并特征和行为来创建新的数据类型。多态方法调用允许一种类型表现出与其他相似类型之间的区别,只要他们都是从同一基类导出而来的。
        多态(也成作动态绑定,后期绑定,或运行时绑定)
8.1 再论向上转型
        对象既可以作为它自己本身的类型使用,也可作为它的基类使用。把这种对某个对象的引用视为对其基类类型的引用的做法称为向上转型。
               package chapter8;
import chapter8.Wind;
/*@name Bath.java
* @describe  8.1 再论向上转型
* @since 2013-06-18 0:36
* @author 张彪
*/
public class Music {
        public static void tune(Instrument i){
                i.play(Note.C_SHARP);
        }
       
        public static void main(String[] args){
                Wind w=new Wind();
                tune(w);   // 向上转型     此处的参数应该是Instrument,但是传入的是导出类Wind
         }
}

        8.1.1 忘记对象类型
                为什么所有人故意忘记对象的类型呢???
               
8.2 转机
        8.2.1 方法调用绑定
                将一个方法的调用同一个方法的主体关联起来被称为绑定。
                前期绑定---在程序运行前进行绑定。
                后期绑定---在运行时根据对象的类型进行绑定。
                     Java中除了static方法和final方法(private方法属于final方法)之外,其他所有的方法都是后期绑定。这意味着通常情况下,我们不必判定是否应该进行后期绑                           定----它会自动发生。
                为什么要将某个方法声明为final呢???
                R:1 防止他人覆盖该方法。2 可以有效“关闭”动态绑定,或者说告诉编译器不需要对其进行动态绑定。这样编译器就可以为final方法调用生成更有效的代码。大多数情况                           下,这样做不会对程序性能有什么改观。所以,最好根据设计来决定是否使用final。
               
        8.2.2 产生正确的行为
                具体例子为chapter8\shape\Shape.java
        8.2.3 可扩展性
                多态是一项让程序员“将改变的事物与未变的事物分离开来”的重要技术。
        8.2.4 缺陷:“覆盖”私有方法
                结论:只有非private方法才可以被覆盖。
        8.2.5 缺陷:域与静态方法
                    package chapter8.super1;
/*@name Bath.java
* @describe  8.2.5 静态方法行为不具有多态性
* @since 2013-06-19 0:25
* @author 张彪
*/
class StaticSuuper{
        public static String staticGet(){
                return "Base staticGet";
        }
        public String dynamicGet(){
                return "Base dynamicGet";
        }
}

class StaticSub extends StaticSuuper{
        public static String staticGet(){
                return "Driver staticGet";
        }
        public String dynamicGet(){
                return "Driver dynamicGet";
        }
}

public class StaticFileAccess {
        //静态方法与类,而并非与单个对象相关联
        public static void main(String[] args){
                StaticSuuper sb= new StaticSub();
                System.out.println(sb.staticGet());   //Base staticGet
                System.out.println(sb.dynamicGet());  //Driver dynamicGet
        }
}
8.3 构造器与多态
                尽管构造器并不具有多态性(它们实际上是static方法,只不过该static声明是隐式的),但还是非常有必要理解构造器怎样通过多态在复杂的层次机构中运作。
        8.3.1 构造器的调用顺序
                      基类的构造器总是在导出类的构造过程中被调用,而且按照继承层次逐渐向上链接,以使每个基类的构造器都能得到正确的调用。
                      对象调用构造器要遵循下面的顺序:
                                1.调用基类构造器
                                2.按声明顺序调用成员的初始化方法
                                3.调用导出类构造器的主体
                               
        8.3.2 继承与清理
                对象销毁的顺序应该和初始化顺序相反,对于字段则意味着与声明的顺序相反(因为字段的初始化是按照声明的顺序进行的)。对于基类,(遵循C++中析构函数的形式),应先对导出                   类进行清理,然后才是基类。

             //如果成员对象存在一个其他一个或多个对象共享的情况,问题就变的比较复杂。
             package chapter8;
/*@name Bath.java
* @describe  8.3.2 继承与清理
* @since 2013-06-19 21:36
* @author 张彪
*/
//使用引用计数器来跟踪仍旧访问着共享对象的对象数量

class Shared{
        private int refcount=0;
        private static long counter=0;
        private final long id=counter++;
        public Shared(){
                System.out.println("Creating "+this);
        }
        public void addRef(){
                refcount++;
        }
        protected void dispose(){
                if(--refcount == 0){
                        System.out.println("dispose "+this);
                }
        }
        public String toString(){
                return "Shared "+id;
        }
}

class Composing{
        private Shared shared;
        private static long counter=0;
        private final long id=counter++;
        public Composing(Shared shared){
                System.out.println("Creating "+this);
                this.shared=shared;
                this.shared.addRef();
        }
        protected void dispose(){
                System.out.println("disping "+this);
                shared.dispose();
        }
        public String toString(){
                return "Composing "+id;
        }
}

public class ReferenceCounting {
        public static void main(String[] args){
                Shared s=new Shared();
                Composing[] composing={new Composing(s),new Composing(s),new Composing(s),new Composing(s) };
                for(Composing c:composing){
                        c.dispose();
                }
        }
}

        8.3.3 构造器内部的多态方法的行为
                构造器调用的层级结构带来了一个有趣的两难为题。如果在一个构造器的内部调用正在构造的对象的某个动态绑定方法,会发生什么情况呢?
             package chapter8;
/*@name Bath.java
* @describe  8.3.3 构造器内部的多态行为的方法
* @since 2013-06-19 21:36
* @author 张彪
*/
class Glyph{
        void draw(){
                System.out.println("Glyph.draw() ");
        }
        Glyph(){
                System.out.println("Glyph before draw() ");
                draw();
                System.out.println("Glyph after draw() ");
        }
}

class RoundGlyph extends Glyph{
        private int radius=1;
        RoundGlyph(int r){
                radius=r;
                System.out.println("RoundGlyph.RoundGlyph(), radius="+radius);
        }
        void draw(){
                System.out.println("RoundGlyph.draw() , radius="+radius);
        }
}

public class PolyConstructors {
        public static void main(String[] args){
                new RoundGlyph(5);
        }
}


/*Glyph before draw()
RoundGlyph.draw() , radius=0
Glyph after draw()
RoundGlyph.RoundGlyph(), radius=5*/
//由输出的结果可知:此时被调用的是RoundGlyph.draw()方法,但是radius的值却是0.  why?????
初始化的实际过程:
1.在其他任何事物发生前,将分配给对象的存储空间初始化为二进制的零。
2.如前所述那也调用基类构造器。此时调用被覆盖的draw()方法(要在调用RoundGlyph构造函数之前调用),由于步骤1的缘故,    我们此时会发现radius的值为0。
3.按照声明的顺序调用成员的初始化方法。
4.调用导出类的构造器主体

注意:在编码构造器时有一条有效的准则:"用尽可能简单的方法使对象进入正常状态,如果可以的话,避免调用其他方法"。在构造器内部,唯一能够安全调用的那些方法是基类中的final方法(也适用于private方法,它们自动属于final方法),这些方法不会被覆盖,因此也就不会产生令人惊讶的问题。
8.4 协变返回类型
        Java SE5中添加了协变返回类型,它表示在导出类中的被覆盖的方法可以返回基类方法的返回类型的某种导出类型。
               package chapter8;
/*@name Bath.java
* @describe  8.4 协变返回类型
* @since 2013-06-19 22:36
* @author 张彪
*/

//Java SE5中添加了协变返回类型,它表示在导出类中的被覆盖的方法可以返回基类方法的返回类型的某种导出类型。

class Grain{
        public String toString(){return "Grain";};
}
class Wheat extends Grain{
        public String toString(){return "Wheat";};
}
class Mill{
        Grain process(){return new Grain();};
}
class WheatMill extends Mill{
        Wheat process(){return new Wheat();};
}
public class CovariantReturn {
        public static void main(String[] args){
                Mill m=new Mill();
                Grain g=m.process();
                System.out.println(g);   //Grain
                m=new WheatMill();
                System.out.println(m.process());  //Wheat
        }
}

8.5 用继承进行设计
        当我们在使用现成的类来建立新类时,如果首先考虑使用继承技术,反倒会加重我们的设计负担。
        更好的方式是选择“组合”,尤其是不能十分确定应该使用哪一种方式时。组合不会强制我们的程序设计进入继承的层次结构中。
       
        8.5.1 纯继承与扩展
                纯粹的“is--a”关系:即导出类的方法和基类的方法完全一样。
                “is--like--a”关系:即导出类除了有基类的方法外,还有自己扩展的方法。
        8.5.2 向下转型与运行时类型识别
                由于向上转型(在继承层次中向上移动)会丢失具体的类型信息,所以我们就想,通过向下转型---也就是在继承层次中向下移动---应该能够获取类型的信息。
                package chapter8;
/*@name Bath.java
* @describe  8.5.2 向下转型
* @since 2013-06-19 22:54
* @author 张彪
*/
class Useful{
        public void f(){}
        public void g(){}
}
class MoreUseful extends Useful{
        public void f(){}
        public void g(){}
        public void v(){}
}

public class RTTI {
        public static void main(String[] args){
                Useful[] x={new Useful(),new MoreUseful()};
                ((MoreUseful)x[1]).v();
        }
}

8.6 总结
        多态意味着“不同的形式”。在面向对象的程序设计中,我们持有从基类继承而来的相同的接口,以及使用该接口的不同形式;不同版本的动态绑定方法。




       
                                                                                                                2013-06-19 23:04 记 @@tangxiacun.tianhequ.guanzhou
0
6
分享到:
评论

相关推荐

    Java第8章 继承和多态含源代码

    Java第8章 继承和多态含源代码 Java第8章 继承和多态含源代码Java第8章 继承和多态含源代码 Java第8章 继承和多态含源代码 Java第8章 继承和多态含源代码 Java第8章 继承和多态含源代码

    第8章-- virtual函数 与多态

    第8章--virtual函数与多态

    Java程序设计:第8章 继承和多态.ppt

    Java程序设计:第8章 继承和多态.ppt

    C++程序设计基础教程 苏大C++程序设计教程(第二版) 第12章 多态(共8页).pptx

    C++程序设计基础教程的第12章主要探讨了多态这一核心的面向对象编程概念。多态(Polymorphism)是C++中一个至关重要的特性,它允许一个接口(函数或运算符)根据调用时的具体对象类型表现出不同的行为。在本章中,...

    c++第八章 继承与多态课件ppt

    继承和多态是C++中面向对象编程的两个核心概念,它们极大地增强了代码的灵活性、复用性和可扩展性。 **继承(Inheritance)** 继承是面向对象编程的基础,允许我们创建一个新的类(派生类)来扩展已有的类(基类)...

    Unity基础 C# 第六章 继承与多态.pptx

    ### Unity基础 C# 第六章 继承与多态 #### 一、继承的基本概念 在面向对象编程中,继承是一种强大的工具,它允许我们基于现有的类定义新的类。这不仅可以减少代码重复,还能使代码结构更加清晰。通过继承,子类会...

    C 程序设计课件:第八章 继承与多态.ppt

    【C++程序设计课件:第八章 继承与多态】 在面向对象程序设计中,继承和多态是两个核心概念,它们极大地增强了代码的复用性和灵活性。本课件详细介绍了C++中这两个概念及其相关知识。 **继承(Inheritance)** ...

    C#面向对象程序设计案例教程

    第1章 C#入门 ...1.1.2 认识C≠语言 1.2 Visual Studio.NET集成开发环境简介 1.2.1 VS.NET起始页 ...第8章 多态 第9章 接口 第10章 异常处理 第11章 委托和事件 第12章 文件操作 第13章 课程设计 参考文献

    第8章动物类派生——继承与多态.ppt

    继承与多态 继承是面向对象编程(Object-Oriented Programming)中的一种机制,允许一个类继承另一个类的属性和行为。通过继承,子类可以重用父类的代码,减少代码的冗余和重复。同时,继承也可以实现多态性,即...

    C++ 程序设计课件:第八章 继承与多态.ppt

    在C++语言中,继承与多态是面向对象编程的两个核心特性,它们不仅提供了代码复用的机制,还极大地增强了程序设计的灵活性和可扩展性。理解这些概念对于掌握C++的精髓至关重要。 首先,让我们深入探讨继承。继承是...

    C++编程思想.rar

    第8章内联函数 第9章命名控制 第10章引用和拷贝构造函数 第11章运算符重载 第12章动态对象创建 第13章继承和组合 第14章多态和虚函数 第15章模板和包容器类 第16章多重继承 第17章异常处理 第18章运行时类型识别

    类的封装、继承和多态

    第1章 Java概述 第2章 Java语言基础 第3章 类的封装、继承和多态 第4章 接口、内部类和Java API基础 ...第8章 Applet应用程序 第9章 输入/输出流和文件操作 第10章 网络通信 第11章 数据库应用 第12章 综合应用设计

    java面向对象程序设计课程每章ppt(共15章+复习1章).zip

    第10章 static修饰符.pptx 第10章 枚举.pptx 第11章 异常和断言.pptx 第12章 JDK8中的日期.pptx 第12章 字符串、日期.pptx 第13章 容器和泛型.pptx 第14章 流与文件(1)....第8章 包装器类.pptx 第9章 内部类.pptx

    北大青鸟C#第六章 初始继承和多态参考答案.zip

    "北大青鸟C#第六章 初始继承和多态参考答案.zip"这个压缩包文件包含了与北大青鸟S2阶段C# OOP相关的上机练习、课后作业和示例的解答,重点讲解了继承和多态这两个关键的OOP特性。 1. 继承:继承是面向对象编程中的...

    21天学会C++(随书源码)

     第8章 指针  第9章 构造数据类型  第10章 类和对象  第11章 继承  第12章 多态  第13章 运算符重载  第14章 输入/输出流  第15章 文件  第16章 命名空间  第17章 引用与内存管理  第18章 标准...

    第十二章Python继承和多态习题与答案--中文

    #### 8. 对象的创建过程 **示例 12.8** ```python class A: def __new__(cls): cls.__init__(cls) print("A's __new__() invoked") def __init__(self): print("A's __init__() invoked") class B(A): def __...

    Java语言程序设计ppt第十一章(继承和多态)

    Java语言程序设计ppt第十一章(继承和多态) 本章节主要讲解Java语言中的继承和多态机制,包括继承的定义、继承的应用、多态性和动态绑定等知识点。 一、继承的定义 继承是一种机制,允许一个类继承另一个类的...

    完整版 Java编程基础入门教程 Java语言程序设计 第5章_继承与多态(共61页).ppt

    【完整课程列表】 完整版 Java编程基础入门教程 ...完整版 Java编程基础入门教程 Java语言程序设计 第8章_多线程与异常处理(共72页).ppt 完整版 Java编程基础入门教程 Java语言程序设计 第9章_Applet(共40页).ppt

Global site tag (gtag.js) - Google Analytics