重载是不是多态?重载是不是面向对象?

龙鞥 2009-05-10 04:58:05
  这个问题困惑了我一阵子,曾经看尚学堂马士兵的授课,说多态必须具备三大特征:子类继承父类,子类覆盖父类,父类指向子类。如果是这样的话,就说明只有继承关系才是多态的先决条件。而网上所能查到的资料,大部分支持的观点是重载是多态,没提到多态,就提到了override和overload区别,令人生疑。还有模糊地说法说的是重载算是广义的多态。

常看到文章说,掌握面向对象语言的高级知识,包括重载、构造函数、继承、多态等。把重载跟多态并列,而且在大部分书籍讲课的时候也好像是把他们提出来的,感觉不是一回事。

及至近日,看到一位仁兄写了一篇文章阐明,重载因为针对的是方法,违反了面向对象的概念。而面向对象的三大特性之一是多态,由此可见,重载不是面向对象,而是面向方法,故不是多态。

感觉说法可以认同。

但是恰恰他的论点提到重载非面向对象,又跟基本上书籍所提及的重载是面向对象编程的一个重要点相违背,令我又产生动摇,于是我就想问,重载到底是不是面向对象的,他到底是不是多态?谁能给与准确回答?
...全文
2659 45 打赏 收藏 转发到动态 举报
写回复
用AI写文章
45 条回复
切换为时间正序
请发表友善的回复…
发表回复
gene_feng 2010-08-30
  • 打赏
  • 举报
回复
讨论得很透彻,学习了,大家一起加油
龙鞥 2009-06-12
  • 打赏
  • 举报
回复
分送完。等着根据大家的讨论,总结下。:)
分不能追加了,还有一些有见地的可能漏了。不好意思。:)
visulcer 2009-06-11
  • 打赏
  • 举报
回复
严格地说,两者根本就没有一点关系
另外,不要把重载和重写混淆了
龙鞥 2009-06-11
  • 打赏
  • 举报
回复
谢谢各位,大家讨论得很好,让我对面向对象有了更好的理解。晚上再好好读读,并追加分。大家看来观点并不一样,但是却给了不同的理解思路。
icesnows 2009-05-22
  • 打赏
  • 举报
回复
[Quote=引用 36 楼 WuBill 的回复:]
不少人对多态的回答是,允许同名函数存在。
这种回答显然没有抓住多态的本质。

多态是指只有到运行时才能确定要执行的代码,即指的是后绑定,这样Overload就不属于多态。
在C++语言中,如果不将Override方法声明为Virtual的,也应该不属于多态。

不过话又说回来,很多书上说overload是方法意义上的多态,都是些名词之争
关键是自己要理解各自的意义,会用万岁!!
[/Quote]

我赞同这个观点,多态应该强调的是后绑定late bingding

题目的重载你到底是指overload还是override啊?
有把override翻译成重载的
zhengqiqiqinqin 2009-05-22
  • 打赏
  • 举报
回复
多态是由重载体现的!!
duanjianbo26 2009-05-22
  • 打赏
  • 举报
回复
[Quote=引用 24 楼 ZangXT 的回复:]
我见过的资料中,
比如《C++程序设计语言》,将多态分为两类,虚函数提供的东西称作运行时多态,模板提供的为编译时多态和参数式多态。
《C++ Primer》采用的说法同上。
《编译原理:技术与工具》中提到的多态介绍,的是参数化多态(注意不是重载,而是类似模板的机制)。
一般java的书中,提到的多态自然是跟继承相关的了。
其实归纳一下,很容易看出来,上面的运行时多态和参数式多态的一致的地方:调用的方式一致。…
[/Quote]
ZangXT看的书还真是不少啊!
小灰狼 2009-05-22
  • 打赏
  • 举报
回复
重载
建议楼主读成(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() 方法。而员工如何实现他们的工作方法却只有精确到子类才能确定,因为不同的工种工作的方式是不一样的。


使用多态可以增强系统的灵活性,降低模块之间的耦合。因为我们很多时候都关心对象的父类型,而忽略它更精确的类型,比如上面的老板叫大家回去工作时,他是对全体员工说的,在这句放中,指的是“员工”类型,而不是精确的类型。再比如我们上饭店吃完饭买单时,只关心你是一个顾客(“人”类),而不会关心你的精确类型,也不会关心你是否在哪里工作,更不会关心是不是一个有孩子的父亲。

qsrock 2009-05-20
  • 打赏
  • 举报
回复
建议不懂得人去看看thinking in java
WuBill 2009-05-20
  • 打赏
  • 举报
回复
不少人对多态的回答是,允许同名函数存在。
这种回答显然没有抓住多态的本质。

多态是指只有到运行时才能确定要执行的代码,即指的是后绑定,这样Overload就不属于多态。
在C++语言中,如果不将Override方法声明为Virtual的,也应该不属于多态。

不过话又说回来,很多书上说overload是方法意义上的多态,都是些名词之争
关键是自己要理解各自的意义,会用万岁!!
xnjnmn 2009-05-19
  • 打赏
  • 举报
回复
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();
}
WuBill 2009-05-19
  • 打赏
  • 举报
回复
讨论很激烈啊,学习。。。
timmf 2009-05-18
  • 打赏
  • 举报
回复
[Quote=引用 27 楼 xiajun07061225 的回复:]
多态是基于对抽象方法的覆盖来实现的,用统一的对外接口来完成不同的功能。重载也是用统一的对外接口
来完成不同的功能。那么两者有什么区别呢?
重载,是指允许存在多个同名方法,而这些方法的参数不同。重载的实现是:编译器根据方法不同的参数表
,对同名方法的名称做修饰。对于编译器而言,这些同名方法就成了不同的方法。它们的调用地址在编译期
就绑定了。
多态:是指子类重新定义父类的虚方法(virtual,abstract)。…
[/Quote]
不错
bolink5 2009-05-18
  • 打赏
  • 举报
回复
如果让你选择一项面向对(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
KingZChina 2009-05-18
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 YidingHe 的回复:]
管他那么多,你自己写几个练习,会用就行了,少听那些人故弄玄虚。
[/Quote]

顶 俺们国家的专家就喜欢弄的特深奥 其实有些问题很容易理解的 那些专家净整些自己编的专业名词忽悠别人 其实就是1+1=2.。。。。
kaylg 2009-05-17
  • 打赏
  • 举报
回复
我也刚学java,个人理解重载一般发生在一个类中满足不同参数的方法,重写就要关系到继承了,就是父类的方法不能满足子类的需求,于是子类要重写这个方法,来覆盖父类的方法;理解的浅,没有上面的高手们说的好
shao8924 2009-05-17
  • 打赏
  • 举报
回复
恩,都看了,学习学习
hillslek 2009-05-17
  • 打赏
  • 举报
回复
xuexi
没有昵称阿 2009-05-17
  • 打赏
  • 举报
回复
多态是基于对抽象方法的覆盖来实现的,用统一的对外接口来完成不同的功能。重载也是用统一的对外接口
来完成不同的功能。那么两者有什么区别呢?
重载,是指允许存在多个同名方法,而这些方法的参数不同。重载的实现是:编译器根据方法不同的参数表
,对同名方法的名称做修饰。对于编译器而言,这些同名方法就成了不同的方法。它们的调用地址在编译期
就绑定了。
多态:是指子类重新定义父类的虚方法(virtual,abstract)。当子类重新定义了父类的虚方法后,父类根据
赋给它的不同的子类,动态调用属于子类的该方法,这样的方法调用在编译期间是无法确定的。
不难看出,两者的区别在于编译器何时去寻找所要调用的具体方法,对于重载而言,在方法调用之前,编译
器就已经确定了所要调用的方法,这称为“早绑定”或“静态绑定”;而对于多态,只有等到方法调用的那一刻
,编译器才会确定所要调用的具体方法,这称为“晚绑定”或“动态绑定”。

资料来源:学网(www.xue5.com),原文地址:http://www.xue5.com/itedu/200707/130577.html
dancingtiger 2009-05-17
  • 打赏
  • 举报
回复
这得自己总结
加载更多回复(25)

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧