我之理解Java的四个基本特征

来源:互联网 发布:c语言大小写转换 编辑:程序博客网 时间:2024/06/07 01:40

抽象、封装、继承、多态性,这是Java(或者说面向对象的编程语言)的四个基本特征,尽管有人已经在说OOP快挂了,但是我们这些coder还是暂时不用考虑那么多,就像XP所倡导的——“只为今天,不考虑明天”

 

抽象,什么是抽象呢,我们知道绘画有抽象派、写实派,写实即是画的很逼真,跟真实事物很像,甚至就像照片一样,而抽象派则画的不那么容易让人认出了,虽然你大概还是猜得出这画的是一个人,但他只有鼻子和嘴巴,头还像S型一样扭着,更抽象的就是一片色彩,像是泼了各种颜色的油漆在上面,你看不懂,大师的画哪能让你轻易看懂呢,或者你也可以说看的懂,你说它是什么就是什么,只要你解释的通。现在我们来看程序里的抽象,我们可以定义一个Man类型,跟绘画里的抽象有几分相似,他只有鼻子和嘴巴,你或许会问,为什么没有眼睛、耳朵和其他一个人所应该具有的所有特征(器官)呢?The answer is:我们只需要鼻子和嘴巴,至少在目前。这就是抽象,抽取出事物中的特征,而且不是全部特征,是我们当前需要的,如果以后我们觉得应该给Man加上眼睛和耳朵,那我们再加上,除了特征,还有行为,既然Man有了nose和mouth,我们理所当然的认为他能闻味道和吃东西什么的,所以我们可以在往Man类里加上两个表示行为的smell()方法和eat()方法,有必要的话我们还可以让Man能够呼吸和讲话,但是不管你加了多少特征和行为进去,Man仍然不可能完全地完完整整的表示一个人,它始终是一个抽象的东西,就好比绘画不管是哪个门派,它其实都属于一门抽象的艺术,不管你画得多么惟妙惟肖、呼之欲出,它仍然只是一幅画而已,它所呈现的不是真实的事物,而只是它们的抽象,不同的只是抽象的方式、有多抽象而已。至于Java中用abstract关键字明确表示的抽象类和抽象方法,你大可以把它们当做Java中的抽象派画作,它们的具体实现自然就是写实派画作了。

 

封装,就像前面讲的,我们分析并抽取出一件事物的特征和行为(这些特征和行为应该都是针对我们当前需求或者我们预见今后要用到的),然后把它定义到一个类里,这即是封装,亦即我们可以说把特征和行为封装到一个类里,还有一个术语叫隐藏实现,当然封装肯定不是把所有东西都藏起来了,封的死死的,它会留一些接口出来,这样才能供我们使用,一个完全封死了的类是没有任何作用的,就像一台没有任何接口的裸机一样,没有软驱、光驱,没有USB接口,不能联网,这样一台电脑连操作系统都装不上,所以它没什么用(如果你硬要说可以用它来砸别人脑袋,那就算它还有点用吧)。如果真有这样一个类,不如把它定义为private,但实际上编译器都不准你这么做,甚至连protected都不行,除非是内部类,讲到内部类,这也是要封装的东东之一,是Java里一种比较高级的隐藏实现,通过内部类和接口可以实现多继承的效果。

 

继承,这个术语既好理解又容易让人困惑,有很多人说过我和我爸长的很像,还有很多人说我说话的方式和声音都很像我爸,看来我继承了不少我爸的特征和行为,也有一些人说我某一部分不像我爸而像我妈,那是不是可以说我同时继承了老爸和老妈的一些特征和行为呢,现实中是这样没错,不过在Java里只允许单个继承,也就是说一个类只能有一个基类(父类),多继承会让代码变得混乱,也许其他OOP语言可以多继承,但是这里只讨论Java,遇到上述我的情况,我可以把我定义为继承我老爸,毕竟我跟他更像一点,至于继承于我老妈的地方,那就只好采用覆写(override)的方式了,当然,这里只是简单的打个比方,如果真要为我建一个类型,可得好好设计一下,我没这么简单。继承最大的好处就在于大大增强了代码复用,基类里有的东西(除了private),派生类会继承下来,不用再重复相同的代码,但事实上,大师们告诉我们,真正用的最多的还是合成(composition),而且应尽量考虑合成而不是继承的方式,一般来说关键是分清"is-a"和"has-a"的区别,前者用继承,后者用合成。

 

多态性,说到多态性,这是和继承、接口和实现密切相关的,继承可以让你把多个派生类都当做一个基类来处理,这正是多态性的体现,最常被举的一个例子就是Shape(形状),可以想见它下面能派生出很多类型,Triangle、Square、Pentagon、Hexagon,每个类都覆写了Shape类中的draw()方法,可以分别画出三角形、正方形、五角形、六边形,这时有一个Shapes类,它有一个方法可以画出所有的Shape,这个方法即draw(Shape x),通过upcasting(上传,将派生类转换成基类),我们可以传入任何派生于Shape的子类作为参数,然后方法里会自动调用这些子类的draw方法,它们是在运行时才被确定的,假使没有这种多态性,那我们就得在Shapes类里为每个派生类单独写一个draw()方法,如draw(Triangle x)、draw(Square x)……要是我们再多一些派生类:Circle、Echelon等等等等,那Shapes类就会不断地膨胀膨胀,撑死了。基于这种多态性,我们可以定义Shape a = new Triangle(); Shape b = new Pentagon();等等,编译器不会报错,并且这样的定义方式是被鼓励的。接口和它们的实现类在多态性上的体现则是和继承一致的。

原创粉丝点击