这个问题困惑了我一阵子,曾经看尚学堂马士兵的授课,说多态必须具备三大特征:子类继承父类,子类覆盖父类,父类指向子类。如果是这样的话,就说明只有继承关系才是多态的先决条件。而网上所能查到的资料,大部分支持的观点是重载是多态,没提到多态,就提到了override和overload区别,令人生疑。还有模糊地说法说的是重载算是广义的多态。      常看到文章说,掌握面向对象语言的高级知识,包括重载、构造函数、继承、多态等。把重载跟多态并列,而且在大部分书籍讲课的时候也好像是把他们提出来的,感觉不是一回事。      及至近日,看到一位仁兄写了一篇文章阐明,重载因为针对的是方法,违反了面向对象的概念。而面向对象的三大特性之一是多态,由此可见,重载不是面向对象,而是面向方法,故不是多态。      感觉说法可以认同。      但是恰恰他的论点提到重载非面向对象,又跟基本上书籍所提及的重载是面向对象编程的一个重要点相违背,令我又产生动摇,于是我就想问,重载到底是不是面向对象的,他到底是不是多态?谁能给与准确回答?

解决方案 »

  1.   

    多态的三大特征: 要有重写,要有继承,父类指向子类
    楼主还是没理解 多态 你可以看下 JAVA编程思想这本书,讲的很详细
    关于重载 这个文章很详细了
    http://baike.baidu.com/view/126530.htm
      

  2.   

    多态必须有重载,但是单纯的重载不是多态。
    override一般发生在继承其他类的时候,重新实现该方法。
    overload一般发生在同一个类中,同一函数名不同的参数。
      

  3.   

    重载是跟面向对象无关的。
    现在的书一般是没有问题的,但是有些垃圾书里所谓的重载指的是(override),早期术语翻译不一致而已。
      

  4.   

    细化一下4L兄弟所说的:override在早期正式的书中有翻译为“越位”的,也就是现在大家说的“重写”了。
      

  5.   

    不是Thinking in C++吧?呵呵
      

  6.   

    多态包括有静态多态和动态多态,一般静态多态是在编译期,由Java编译器根据参数列表的不同,来决定绑定相应的重载方法;
    多态多态是在程序运行期间,由JVM根据引用的对象,来决定绑定相应的方法。
      

  7.   

    看了引用网址的东西,如下:
    --------------------------------
     重载是不是多态?
      re:
      重载还是一种是多态吧,有四种形式的多态
      1.虚函数多态
      2模板多态
      3重载
      4转换
      所谓的动态和静态区分是另一种基于绑定时间的多态分类,严格来说,重载是编译时多态,即静态多态,根据不同类型函数编译时会产生不同的名字如int_foo和char_foo等等,以此来区别调用。故重载仍符合多态定义——通过单一标识支持不同特定行为的能力,只是重载属于静态多态,而不是通过继承和虚函数实现的动态多态。
      另一中说法:
      重载(overload)和多态无关,真正和多态相关的是覆盖(override)。
      当派生类重新定义了基类的虚拟方法后,基类根据赋给它的不同的派生类引用,动态地调用属于派生类的对应方法,这样的方法调用在编译期间是无法确定的。因此,这样的方法地址是在运行期绑定的(动态邦定)。
      结论就是:
      重载只是一种语言特性,与多态无关,与面向对象也无关。
    -----------------------------
        我就是想问,这两种说法,到底有没有定论。那重载到底是不是多态。我提到的多态要有三大特性,是尚学堂马士兵的视频教程里提到的,即:多态的三大特征: 要有重写,要有继承,父类指向子类 。如果按照他的意思,他是说多态是继承衍伸出来的。他比较支持第二种说法了。
        所以令人很迷惑。
      

  8.   

    我见过的资料中,
    比如《C++程序设计语言》,将多态分为两类,虚函数提供的东西称作运行时多态,模板提供的为编译时多态和参数式多态。
    《C++ Primer》采用的说法同上。
    《编译原理:技术与工具》中提到的多态介绍,的是参数化多态(注意不是重载,而是类似模板的机制)。
    一般java的书中,提到的多态自然是跟继承相关的了。
    其实归纳一下,很容易看出来,上面的运行时多态和参数式多态的一致的地方:调用的方式一致。
    重载不同,比如a.text(1),a.test(1,2),并不是对于同一种接口有不同的反映,因为接口本身就不同。所以,最好不要把重载归到多态中,当然你可以在高一层,说这是对同一个名字的多态……
      

  9.   

    java 重载和重写都是实现多态的方式.前者是编译期间多态,后者则是运行期多态具体代码如下(我是引用CSDN的一帖子,免得我在写了,呵呵)public class Base{
    int a,b;
    public Base(int x,int y){
    a = x;
    b = y;
    }
    public int add(){
    return (a + b);
    }
    public void add(int x,int y){
    int z;
    z = x + y;
    }
    }
    上面这段代码就是重载~~~他有三个特征
    1:方法名必须一样 “add()“。
    2:返回类型可以不一样 就象是 ”int “和”void“.
    3:参数可以不一样 就是add() 和add(int x,int y)这样的。
    public class Base{
    int x,y;
    public void add(){
    int z;
    z = x + y;
    }
    }
    public class Child extends Base{
    int x,y;
    public void add(){
    int z;
    z = x + y;
    }
    public static void main(string [] args){
    Base b = new Child();
    b.add();
    }
    }
    下面这个例子就是重写,他实现了多态~~
    重写的要求是,方法名必须一样,返回类型必须一样,传入的参数必须一样
    在main函数中定义父类的对象,但是用子类去实例化他,这样就可以通过父类的对象调用到子类的方法。重载是在父类中进行的.这是最大的区别
      

  10.   

    多态是基于对抽象方法的覆盖来实现的,用统一的对外接口来完成不同的功能。重载也是用统一的对外接口
    来完成不同的功能。那么两者有什么区别呢?
    重载,是指允许存在多个同名方法,而这些方法的参数不同。重载的实现是:编译器根据方法不同的参数表
    ,对同名方法的名称做修饰。对于编译器而言,这些同名方法就成了不同的方法。它们的调用地址在编译期
    就绑定了。
    多态:是指子类重新定义父类的虚方法(virtual,abstract)。当子类重新定义了父类的虚方法后,父类根据
    赋给它的不同的子类,动态调用属于子类的该方法,这样的方法调用在编译期间是无法确定的。
    不难看出,两者的区别在于编译器何时去寻找所要调用的具体方法,对于重载而言,在方法调用之前,编译
    器就已经确定了所要调用的方法,这称为“早绑定”或“静态绑定”;而对于多态,只有等到方法调用的那一刻
    ,编译器才会确定所要调用的具体方法,这称为“晚绑定”或“动态绑定”。 资料来源:学网(www.xue5.com),原文地址:http://www.xue5.com/itedu/200707/130577.html
      

  11.   

    我也刚学java,个人理解重载一般发生在一个类中满足不同参数的方法,重写就要关系到继承了,就是父类的方法不能满足子类的需求,于是子类要重写这个方法,来覆盖父类的方法;理解的浅,没有上面的高手们说的好
      

  12.   

       如果让你选择一项面向对(Object Oriented,后文简称OO)象最重要的或者最能表现OO特点的技术特征,会是什么?
       封装(wrap)、继承(inheritance)、重载(override)还是多态(polymorphism),亦或是其他?
    在我看来,答案无疑将是多态。封装是优点,继承是基础,重载是特点,而多态则是特征。
      虽然这四者缺一不可,无论少了哪一个,就像一个人缺胳膊少腿,使OO将不再是完整的,但是前三者对于OO来说好比鼻子耳朵,而多态则是生殖器,没有多态的OO就象是被阉割的雄性,已经失去其典征。 什么是多态?  简单来说,多态是具有表现多种形态的能力的特征,在OO中是指,语言具有根据对象的类型以不同方式处理之,特别是重载方法和继承类这种形式,的能力。多态被认为是面向对象语言的必备特性。多态有多种分类,通过了解这些分类可以更丰满对其认识,在这里就不再罗列,请各位参考 wiki大百科  和 javaworld . 
    多态与泛型(generic)  多态实际上就是泛型。
       所谓泛型就是指我们不为特定的类型进行专门编码,而采用对不同类型进行通用编码的方式,无论是数据结果还是算法。
      传统的泛型是指类似以Template function的方式使参数一般化,典型的应用是C++ STL,比如List、Vector以及algorithm。
      而OO已能通过接口(Interface)和抽象类(Abstract Class)进行真正意义上的泛型了。在我看来,这就是OO最精彩的地方,也就是多态的威力。而对于传统意义上的Generic,我始终觉得其作用已经今不如昔了。 多态和继承(Inheritance)  严格来说,多态与继承、重载并不是孤立的,他们之间存在着紧密的联系,多态是建立在这两者的基础之上的(实际上继承就有用重载这一特性)。
      传统的多态实际上就是由虚函数(Virtual Function)利用虚表(Virtual Table)实现的(早期C模拟OO特性时使用最多,C++的实现也是,后来的技术未作研究,是否使用VT不得而知),自然是离不开继承,换句话说多态实际上覆盖了继承。  正是由于继承与多态的紧密联系,使得我们很容易张冠李戴,那么如何区别呢?  举个常用的例子:Abstract Class Sharp implement IHaveSide {
     public bool isSharp(){
       return true;
     }
     public abstract int getSides();
    }Class Triangle extends Sharp {
     public override int getSides() {
       return 3;
     }
    }Class Rectangle extends Sharp {
     pubilc override int getSides() {
      return 4;
     }
    }那么这种类的关系叫做继承,下面这种使用方式也是继承所带来的:
    Triangel tri = new Triangle();
    println("Triangle is a type of sharp? " + tri.isSharp());而这种方式则是多态:
    Sharp sharp = new Rectangle();
    println("My sharp has " + sharp.getSides() + " sides.");这两者区别在哪?很显然,继承是子类使用父类的方法,而多态则是父类使用子类的方法。其技术上的区别是绑定时期,晚期绑定一定是多态。 现代软件设计  现代软件大量的使用框架、模式(非特指Deisgn Pattern),也就是将软件开发的一些共性进行抽象,提出普遍适用的软件结构。
      无论是框架还是模式,他们都有一些明显的共同点 — 使用xml配置对象,大量使用接口采用所谓面向接口的方法,利用反射实现。  为什么要接口?因为需要抽象,需要将未知的对象在已有的框架中表现。
      如何实现接口?多态!所谓反射,实际上就是一种晚期绑定的技术,这个技术实质上表现出来的就是多态这一特征。  面向方面开发(Aspect Oriented Programming)是一个热点,也是现代软件发展的趋势。定制、组件装配的软件开发方式在应用越来越复杂、需求变化越来越快的今天显得日趋重要。那么如何才能使今天的软件能够适应明天需要呢?如何使我开发速度更快?如何能更容易的修改应用?AOP则是解决这些问题的有效手段。
      让我们看看框架容器的主要模式,Inversion of Control Containers(IoC)/Dependency Injection(包括setter injection, construct injection, interface injection等),其主要好处就是类之间的依赖,通过运行期的查找来进行绑定。那么他的基础是什么呢?还是多态!
      我们可以看到,在现代软件的开发中,无数的思想象火花一样跳动。其中一类很重要的思想就是建立在多态这样一个很基本的特性,甚至可以说是一个语言概念之上的。在这里希望通过这篇文章抛砖引玉,引起更多的对与当今软件发展发向的思考,同时探究其根源。 
      出自:http://blog.csdn.net/njchenyi/archive/2007/03/04/1520440.aspx
      

  13.   

    7.3. 多态(polymorphism) 
    多态:一个对象变量可以指向多种实际类型的现象。
    7.3.1. 方法的覆盖(overridding)
    当子类从父类继承一个无参方法,而又定义了一个同样的无参方法,则子类新写的方法覆盖父类的方法,称为覆盖。(注意返回值类型也必须相同,否则编译出错。)
    如果方法参数表不同,则成重载。
    特点:
    1.对于方法的访问限制修饰词,子类方法要比父类的访问权限更高。
    父类为public,那么子类为private则出现错误。
    2.子类抛出的异常应该是父类抛出的异常或其子类。
    7.3.2. 多态的分类
    多态分两种:
    1编译时多态:编译时动态重载;
    2运行时多态:指一个对象可以具有多个类型,方法的覆盖
    这样对于对象而言分为:
    理解运行时多态:
    Car c = new Bus();
    Car编译时类型    编译时检查变量类型是否存在,是否有调用的方法
    Bus运行时类型 实际运行是访问heep中的对象,调用实际的方法。
    运行时多态是由运行时类型决定的
    编译时多态是由编译时类型决定的
    猫,小鸟,狗 都是动物,都可以安上动物的标签。
    Interface Animal{}
    Class Car implements Animal{}
    Class Bird implements Animal{}
    Class Dog implements Animal{}
    方法中
    Animal a = new Car();
    Animal b = new Bird();
    Animal c = new Dog();*方法重载看的是参数的编译时类型public class Animal{
    public static void main(String[] args){ }
    }
    (1)    是覆盖吗?不能多态了
    abstract class MyClass{
    priavate void m();
    }
    class Sub extends MyClass(){
    public void m();
    }
    (2)   错误的修饰符组合
    abstract class MyClass{
    priavate abstract void m();
    }
    class Sub extends MyClass(){
    public void m();
    }
    (3)  5.0 新  非覆盖 
    abstract class MyClass{
    private final void m();
    }
    class Sub extends MyClass(){
    public void m();
    }
      

  14.   

    不少人对多态的回答是,允许同名函数存在。
    这种回答显然没有抓住多态的本质。多态是指只有到运行时才能确定要执行的代码,即指的是后绑定,这样Overload就不属于多态。
    在C++语言中,如果不将Override方法声明为Virtual的,也应该不属于多态。不过话又说回来,很多书上说overload是方法意义上的多态,都是些名词之争
    关键是自己要理解各自的意义,会用万岁!!
      

  15.   

    建议不懂得人去看看thinking in java
      

  16.   


    我赞同这个观点,多态应该强调的是后绑定late bingding题目的重载你到底是指overload还是override啊?
    有把override翻译成重载的
      

  17.   

    重载
        建议楼主读成(zhong 第四声)载,就象一辆客车,本来只能坐30个人,结果坐了50人,我们说它超重(zhong)了。放到一个程序设计语言里,就可以理解成“一个方法本来只有一个入口,或者说它只完成一个功能,但是我们通过设置不同的参数列表,使它的负担更重了”。重写,也叫覆盖,就是子类重新实现了父类的方法。
    其实面象对象并不难理解,可以拿现实中的事物模型来作参考:父类:动物
    子类:人、马、蛇、鸟 是“动物”的子类。
    子类:男人、女人是“人”类的子类,燕子、麻雀是“鸟”的子类。父类是比子类更加“泛”的类型,而子类则是比父类更加“精确”的类型。比如说,“我们昨天捕到一只鸟”和“我们昨天捕到一只麻雀”相比,前者所指的类型更泛,后者说的类型更精确。相应的还有如“那里坐着一个人”和“那里坐着一个女人”等等。重载(overload)不一定是面象对象程序设计语言里有的东西。只要编译器支持,结构化程序设计语言里也可以有重载。
    重写(override)则是与继承有关的概念。它表示父类有一个方法,而到了子类那里,实现的方式不一样,所以必须要改写父类的实现过程。比如,鸟类一般是通过下蛋来繁衍后代,鸟类有一个方法叫"createChildren()",实现时是用下蛋的方式,假设有一种鸟(是“鸟”类的子类)是通过胎生来繁衍后代的,那么这个子类就应该重写 createChildren() 方法。多态说白了就是一个对象有多种类型。
    比如说在上面的模型里,如果“克林顿”是一个“男人”,那么他肯定是一个“人”,显然他也应该是一个“动物”也就是说,在java这样的单继承语言中,子类的一个对象一定是其父类的一个对象,子类的对象同时具有了它的父类、祖父类、祖祖父类......的类型。这是多态的一种形式,所以在java中,子类的一个对象赋值给父类的一个对象时,是不需要作类型转换:
    Human 克林顿 = new Man();
    或者
    Animal 克林顿 = new Human();
    上面说的是从子类到父类。现在看父类到子类,假设我们得到一个“人”类的对象,那么这个人有可能是一个男人,也可能是一个女人,当然如果“男人”和“女人”又有子类的话,也可能是一个“当了父亲的男人”或者“当了母亲的女人”等等。也就是说,一个父类的对象,它有可能是这个父类的众多子类的一个对象,这也是多众的一种情况。在这种情况下,赋值操作就要作类型检查和类型转换了:
    Human human = getHuman(); // 从程序其它模块得到一个 Human 对象
    if(human instanceof Man){
        Man m = (Man)human;
        // 调用 Man 类的方法
    }
    并不是所有的类型都可以相互进行转换,比如在上面的模型中,我们可以把一个“人”的对象转换成“男人”或“女人”的类型,这是进行更精确的类型转换;而要想把一个类型为“马”的对象转换成“人”,或者把一个“男人”转换成“女人”类型显然是行不通的,别说运行时,连编译都通不过。顺着这个思路,我们可以总结出可以和不可以进行类型转换的种种情况。
    很显然,我们可以通过子类的对象调用其父类的公有方法。比如,如果一个动物有一个方法:sleep(),那么我们也可以调用人的对象的 sleep() 方法:
    Man m = new Man();
    m.sleep();
    而不可以通过父类的对象调用子类才有的方法,比如只有“女人”才有的“生孩子”方法,在“人”类的对象中不可以调用:
    Human h = ......
    h.生孩子();
    因为这个时候还不能确定这个人就一定是一个“女人”。
    在java中,多态还表现在抽象类和接口上。抽象类是用来继承的类,如果抽象类没有被继承,则它就没有存在的意义(由此也可以推断出抽象类至少有一个非私有的构造方法,否则编译通不过)。抽象类可以这样理解,可以确定一个类型一定会有一个操作,但是这个操作的实现必须精确到它的子类时才能确定。
    另外看一个模型,一家公司有员工类(Employee),还有其子类:销售(Sales)、市场(Market)、工程师(Engineer)、会计(Accounting)等。某一天老板招所有员工开了个短会,完了之后对所有的员工(Employee)说,大家回去工作吧。
    在这里我们可以认为老板调用了所有员工对象的 continueToWork() 方法。
    可以确定的是,员工类应该有一个方法 continueToWork() 方法。而员工如何实现他们的工作方法却只有精确到子类才能确定,因为不同的工种工作的方式是不一样的。
    使用多态可以增强系统的灵活性,降低模块之间的耦合。因为我们很多时候都关心对象的父类型,而忽略它更精确的类型,比如上面的老板叫大家回去工作时,他是对全体员工说的,在这句放中,指的是“员工”类型,而不是精确的类型。再比如我们上饭店吃完饭买单时,只关心你是一个顾客(“人”类),而不会关心你的精确类型,也不会关心你是否在哪里工作,更不会关心是不是一个有孩子的父亲。