似乎java中的方法缺省就是能够实现多态的。在C++和C#里是virtual的,在VB.Net里是Overridable的。
在我的印象里,这种实现多态的方法,需要在调用时多进行一次间接寻址(使用了C++里的术语,就是在虚函数表中得到具体函数的地址),稍微影响一点点效率。在C++中函数(或者叫类的方法)并不是天生就是可以实现多态的(能够被重写(override),或者说是虚函数)。这应该说是出于效率上的考虑吧。在.net阵营里的C#和VB.net都保留了这一行为特点,即如果不显示声明为可重写的(overridable VB.net或virtual C#),就不可以在调用中实现多态。
请问java中的方法是否是天生就具备多态特性的?如果是,有没有手段声明某个方法不可以实现多态呢?(是用final吗?)如果是这样的话,大家能不能猜测一下java设计者这样设计的初衷呢?他们是根据怎样的研究以及统计数据得出大部分方法都是多态的结论的呢(如果大部分方法不是支持多态的,则语言这样设计就显得有些为了理想而丧失效率了)?
由于我的水平不高,所以产生这样的疑问,希望高手尽量回答我的问题,尤其是最后的讨论。我觉得这样的讨论很可能比较有趣。

解决方案 »

  1.   

    类声明为final或方法声明为final.
      

  2.   

    第一个问题: 答案应该是肯定的吧,java默认是可以实现多态的.第二个问题:要使某个方法不能实现多态的功能,可以有几个途径:1.方法申明为private(此时,该方法隐式调用final修饰关键字;2.显示调用final字段来修饰方法;3,将方法所在的类声明为private或final类型,这样 ,类的所有属性和方法都会隐式final; 4.方法声明为static.第三个问题:就比较麻烦了,我个人认为,每中语言被设计出来,都有她的道理,假如java的设计者将java设计成和C++一样的,那还什么必要呢?直接用C++就行了,你说呢?每种语言都是为不同的目标和满足不同的需要或是为了以不同的途径解决不同的问题的而设计出来的.所以必然会有得失,如果我我们只从语言性能,效率去考虑,就很难得到答案了.为什么C++的控制那么复杂,指针,内存泄露等存在那么多的缺陷,却还要用,而不采取java的形式; 而java的效率,功能等却比不上C++的,而不用C++的那套机制呢? 所以,我们考虑问题应该从每种语言针对的应用领域去理解应该就更容易理解设计者的为什么那样设计,即使是有很多不足的.正如我们知道的那样.C++的目标是强大的功能和控制能力,代价是复杂性提高,程序员要做的事更多,C++有时会牺牲OOP模型以获取性能的提升;Java的目标是兼容性和分布式应用,为此不惜牺牲一些运行速度。个人见解!
      

  3.   

    yanhuaxie(IT Farmer) 的见解很有道理。
    对于多态,我个人认为,虽然牺牲了一点点效率,但提供了强大的能力,这种牺牲是值得的。
    对于大多数方法,假定支持多态也有一定道理,如果需要调用基类中的代码,可以在派生类的方法中使用super关键字。而且,决定使用基类的逻辑还是派生类的逻辑,从OO的角度看,似乎不应是调用者应当关心的逻辑。
    不使用多态,从OO的观点看倒是比较奇怪的事情。一般来讲,如果实例化了某个派生类的实例并将它赋给了一个其父类的引用。通过这个引用调用方法,而执行的是父类的代码,那么我们还派生子类干什么。OO最强大的能力就在于多态。
    然而,我并不对java这种设计有什么意见,只是想多探讨一下该语言某个特性的设计思想。希望在讨论中能够有所收获。欢迎大家多发表见解,对于java语言的设计思想进行深入的探讨。我另外还有一个问题就是关于适应J2ME的Java的一个限制的。问题提在J2ME版里了,如果大家有兴趣,欢迎一起讨论。http://community.csdn.net/Expert/TopicView3.asp?id=5411308
    此外,我还有一个问题,和这个问题的关系不大,但我对延续一个帖子很感兴趣。不知道把不是很相关的内容放在一个帖子里面是否合适,希望大家给点儿建议。只要帖子延续,我会不断追加分数的。还有,如何在不结帖的前提下给分呢?
    我的另外一个问题是:
    很多时候,在某个方法中,需要根据所操作的对象的类型或所实现的接口来决定不同的行为。举个例子:假如需要一个通用的集合类,该类的元素可以是任何类型的数据,而且不要求所有元素都具有相同的类型(换句话说,不适宜使用类似泛型的技术)。对于对象,比较容易处理,然而对于基础类型的数据,比如int,处理起来就不是那么方便了。总觉得使用显式包裹对象(比如Integer)挺别扭的。请大家多提一些思路,谢谢。
      

  4.   

    类声明为final或方法声明为final.
      

  5.   


    to yanhuaxie(IT Farmer):要使某个方法不能实现多态的功能,你提供了以下途径,我比较赞成:
    1.方法申明为private(此时,该方法隐式调用final修饰关键字;2.显示调用final字段来修饰方法;3,将方法所在的类声明为private或final类型,这样 ,类的所有属性和方法都会隐式final; 4.方法声明为static.
    但我想知道,方法申明为private(此时,该方法隐式调用final修饰关键字),你怎么证明它隐式调用final修饰关键字,我想知道,谢谢,能否给我一个测试的方法.
      

  6.   

    呵呵  这个我就没有细细研究过了
    估计得去看java底层的实现机制了
    thinking in java里面说的
      

  7.   

    昨天又去看看了
    C++默认不支持动态绑定,采用的是运行前期绑定的机制,而java采用的是后期绑定.原因:1、对象的创建及破坏方式不同。对象需要的数据位于哪儿,如何控制对象的“存在时间”呢?两种语言的解决方案是不同的。C++认为程序的执行效率是最重要的一个问题,所以它允许程序员作出选择。为获得最快的运行速度,存储以及存在时间可在编写程序时决定,只需将对象放置在堆栈(有时也叫作自动或定域变量)或者静态存储区域即可。这样便为存储空间的分配和释放提供了一个优先级。某些情况下,这种优先级的控制是非常有价值的。然而,我们同时也牺牲了灵活性,因为在编写程序时,必须知道对象的准确的数量、存在时间、以及类型。如果要解决的是一个较常规的问题,如计算机辅助设计、仓储管理或者空中交通控制,这一方法就显得太局限了。2、在一个内存池中动态创建对象,该内存池亦叫“堆”或者“内存堆”。若采用动态绑定方式,除非进入运行期,否则根本不知道到底需要多少个对象,也不知道它们的存在时间有多长,以及准确的类型是什么。这些参数都在程序正式运行时才决定的。若需一个新对象,只需在需要它的时候在内存堆里简单地创建它即可。由于存储空间的管理是运行期间动态进行的,所以在内存堆里分配存储空间的时间比在堆栈里创建的时间长得多(在堆栈里创建存储空间一般只需要一个简单的指令,将堆栈指针向下或向下移动即可)。由于动态创建方法使对象本来就倾向于复杂,所以查找存储空间以及释放它所需的额外开销不会为对象的创建造成明显的影响。除此以外,更大的灵活性对于常规编程问题的解决是至关重要的。3、C++允许我们决定是在写程序时创建对象,还是在运行期间创建,这种控制方法更加灵活。大家或许认为既然它如此灵活,那么无论如何都应在内存堆里创建对象,而不是在堆栈中创建。但还要考虑另外一个问题,亦即对象的“存在时间”或者“生存时间”(Lifetime)。若在堆栈或者静态存储空间里创建一个对象,编译器会判断对象的持续时间有多长,到时会自动“破坏”或者“清除”它。程序员可用两种方法来破坏一个对象:用程序化的方式决定何时破坏对象,或者利用由运行环境提供的一种“垃圾收集器”特性,自动寻找那些不再使用的对象,并将其清除。当然,垃圾收集器显得方便得多,但要求所有应用程序都必须容忍垃圾收集器的存在,并能默许随垃圾收集带来的额外开销。但这并不符合C++语言的设计宗旨,所以未能包括到C++里。但Java确实提供了一个垃圾收集器(Smalltalk也有这样的设计;尽管Delphi默认为没有垃圾收集器,但可选择安装;而C++亦可使用一些由其他公司开发的垃圾收集产品)。
                                                         -----thinking in java