引言:
我接触Java,或者说系统地接触到计算机领域的时间是在三个月前,但在学习及后来的应用之中,对于Java中的“面向对象”的理解与感触逐步加深,颇觉有趣,特此一书自己的理解,恰好近日在整理三月学习的各个部分以应对来年的校招,便想,若有时间的话,也会再将其他的部分一一阐述出自己的理解,以此自我归纳以总结,至于读者,则可以交流或者学习;而我迄今所学,学的是WEB,具体包括了Java,xml,servlet,ajax,orcale数据库,jdbc,html,js,jq,jsp以及struts2的框架,以及一点点Spring框架,因而所举例子,或者视野所限,将会局限于web部分,请读者自行斟酌。
正文:
你是怎么看待世界的呢?
假如你要向一个外星人(能交流却第一次来到地球)阐述地球的存在,你将如何阐述呢?
我想这属于世界观的范畴,每一个人都有其独有的认知世界的方式,而这,也是我渐渐对于Java中“面向对象”产生的感悟——它提供了一种世界观,一种试图阐述世界运行与组成的一种方式。
“面向对象”的一方面认为世界是层级结构的,并且具有一定的范围,这类似于数学中的集合,虽然Java中也有很多的“集合”类,但这两者指代的东西并不相同。正如几乎每一个在初次学习“面向对象”时所学到的一样,任何事物都是对象,“一切皆对象”。
而苹果是一个对象,水果是一个对象,你可以说“苹果”是“水果”,却不能说“水果”是“苹果”,这就体现出了一种层级关系,一种包含的关系,一种指代范围大小的差异,而在Java代码的表现上,就是在“苹果”继承于“水果”的前提下,你可以用“水果”声明一个变量,来创建“苹果”对象。
而在Java中,我猜测为了保证某种合理,为了一定安全性考虑,虽然可以用“水果”来声明“苹果”,但是当这么声明之后,声明的“水果”在表观上将只保留“水果”的特征,而失去了“苹果”独有的部分,虽然其实质,就是一个“苹果”。
在Java代码的表现上,就表现为当用父类(水果)声明变量创建子类(苹果)对象的时候,这个变量将只能被使用父类的方法与属性,因此当你需要使用子类的方法或属性时,需要向下强制转型——这通常也是用父类声明创建子类对象后迟早要做的一件事。
这样做的很大一部分原因是为了方法的复用,更具体的解释下文将会讲解。
而当学到这里,假如再无聊地敲些有关的代码,你就会发现一件有意思的事情——在Java代码中,你同样可以用实现的接口声明来创建一个实现了该接口实体类的对象,而其代码表现,与上述的继承几乎完全相同,即你只能使用声明接口的方法,而不能使用所创建的子类对象的特有方法。
也就是说,“苹果”和“篮球”虽然是两个看似不同的东西,但你可以用同一个“球形”声明变量来同时创建这两个似乎完全不同的对象,仅仅因为其实现了这个“接口”。
这其实是一个能让人接触到本质的发现,通过这个发现,你就该知道,Java所谓的“单继承、多实现”的结构,并没有看起来那样的割裂,因为仅以上述例子论,你其实并没有充足的论据来说明“球类”不是“苹果”或“篮球”的一个父类,而实际也确实如此,虽然“苹果”和“篮球”看似相去甚远,但总有某些共性,这共性,若从数学的集合上来将,则就是交集,而其在Java之中,则是“接口”——这接口,难道不也相当于一种特殊的被继承的父类吗?
因此,一个类单继承的“父类”与多实现的“接口”之间,似乎就仅仅是“extends”和“implements”的区别了,这在较浅的程度上讲,我其实觉得并无不妥。
当然,这里肯定得说明,它们之间的区别并不仅是关键字的区别,更有基于其特性的区别,比如说因为接口只会写出抽象方法,而不会有具体实现,接口可以继承另一个接口,因此当类实现了接口,就需要实现其包含的所有抽象方法,还比如说,因为接口里并不能定义属性,因而只是方法的封装,而不能如父类一般,是类的封装……
这也恰恰说明了接口和父类有所区别的必要性,因此,也只能说其二者,也只是在较浅的程度上相似。
说回上文所说Java通过“类”所提供的“层级结构”的世界观,这种“层级结构”也是多维度的,具体来说,就是其不仅限于上述所举的苹果与篮球的例子,而是在时间上也可以抽离出类来,如Servlet类的init和destroy方法是在不同的时期分别调用——这说起来似乎有些绕,但我想说的是:时间的流逝的一段时期里或者说事物的发展过程同样可以是对象。
而凡谈及世界观,则无形中必限定了一个最大的范围,即“世界”,世界观里的任何事物都超不过世界的定义,Java代码里,对于其同样有一个类对应,即“Object”类,Object类是一切类的父类,而在Java里,称其为“对象”。
这也是我认为其“面向对象”的含义,当知道这点后,上文所说的“强制向下转型”的优越性及必要性就有非常好的例子来论证了,同时,也提供了更多的实际意义。
因为在“强制向下转型”的应用中,通常所声明的变量类型是Object类,这在Java的许多知识中有所体现,我印象最深的,就是设计模式中的工厂模式,他在定义工厂方法的时候声明的返回值类型是Object类,就可以随意在方法中根据条件(通常是String类型),来返回各种类的对象,然后当你使用时,只需强制向下转型成所需的对象就可以了,这在Spring框架的IOC中也有所体现。
另外,Java中有“泛型”的概念,虽然我并不知道其底层的实现,但我猜测,大概也是用了这种方式,因为所谓泛型,不就可以用“Object”类来声明吗?它只是缺少了向下转型的显式步骤,这可能是因为底层帮你做了这个工作。
说到这里,应该可以以Java的视角来回答开篇的两个问题,你是怎么看待世界的呢?Java认为世界万物起于Object,并且以Object为基类向上发展,最终通过不同的方向,演绎出缤纷的世界,而假如要向外星人阐述一个事物的时候,Java将会一层层地阐述,分明而又清晰。
本文最后一部分,将讲述我在学习“面向对象”时最疑惑的地方,那就是为何Java仅仅声明了就好像存在了呢?比如说当new一个Person类的时候,你声明一个name的String属性,Person就有了name,这或许还可以理解一些,可当写了一个run方法,即便它是空的,这个Person就能run了,这难道不令人疑惑吗?因为Java就似乎上帝一样,说有了光,便有了光,可Java不是上帝,它被人使用并且还能有各种各样的实际用处,这与上帝相比,似乎又太过具体了点。
近一个月,我忽然想明白了这个问题,Java的“面向对象”,归根到底,只是一种阐述世界的方式,而不是世界,它同我儿时爱看的小说一样,只是阐述了世界,因此,它只需要说有,那便有了,如同小说,说什么就有什么,区别只是某些人的描写生动些,从而更真实些罢了。
这其实也是我在学习Java时最惊喜的地方,因为我小的时候爱看玄幻仙侠小说,小说除了精彩的故事情节曲折外,每一部小说想象的世界观也是格外令人着迷的,而Java,其实也如同小说,阐述了一种世界观,只是其中曲折的故事情节,就需要我们程序员来书写了。
而我同样认为Java,或者说计算机诸多语言的伟大之处,在于它提供的世界观是开源的,是每一个懂得其规则的人都可以使用的,这是我认为其超越小说,或者说文学作品(因为即便是现实主义的小说,其中世界,也只是作者的世界,而非完全客观的)的地方——文学作品的世界观写出来便定了下来,他人很难对其作出修改,或者使用,其世界是闭塞的,是独属于创作者的,除此之外,文学作品中世界观的逻辑性远比不上计算机世界,但真正客观的世界难道就真如计算机世界中这么层次分明,逻辑严谨吗?
我有时想来,恐怕也并不是。
哈,这可真算的上庄周梦蝶般的无聊了。
2018年3月4日