说烂了的面向对象
我要说的面向对象,其实是一个我自己都觉的有点恶心的东西。
它是java语言入门如此初级的一个概念。作为一个老鸟,你可以吐口水给我,我可以把它们擦干,但作为总结还得说一说。
因为对于一个从来没有接触过编程语言的人来说,就不那么简单了。任何一件简单事情,只是因为你会了,而对于不会的人,就如上天一般的难。
当年作为资深小白的我第一次听老师说起这个概念,脸上写着大大的两个字:"懵逼"。面向对象?对象?面对着对象,呆萌。。。好吧,这个对象和我想的对象是在不太一样。因为老师告诉我,在java的世界里,处处都是对象,如此和谐的一个世界。
而实际上,它只是java语言思考解决问题的一种方式。那就是对于一切要解决的问题,都被归类成了两个方面,是什么,能干什么。是不是和哲学的三大终极问题有点相似:我是谁,我从哪里来,我要去哪里去。看似简单,实际上也是对于这个世界的一种思考。
比如一辆汽车,首相要弄明白的是,什么是汽车,怎样的一个物体可以被称为汽车,应该拥有哪些属性?在java中被称为属性。而汽车有哪些行为?它能跑,喇叭会叫,能前进,能倒退等等这样的行为被称为方法。
再比如公司。公司拥有哪些属性?它在哪里,有多少人,有多少男员工,有多少女员工等等。而公司能做什么?可以经营,创收,交税等等这么多的行为。
如此再来理解一切皆为对象这句话。就是说万事万物,一切可以被看见,被感知的物体或者事情都可以抽象为对象这个东西,被语言所认可。而实际上,当我真正开始用对象这种思路来理解整个世界的时候,还挺可怕的。
接触编程之前,我会以一个人的视角去思考问题。
比如说,从1,4,5,2,3这一串数字中找到最大的一个数,是不是很简单?是啊,这不一眼就看出来了嘛?那只是因为你太年轻了。在一眼就看出来了的过程中,大脑经历了怎样的思考过程。我试着把这个瞬间放大十万倍。首先,我看到了一串数字。这串数字其中的一部分被我记到。我试着从前两个,或者前几个中找到最大值,并且记住这个最大值。然后开始迭代,是否能找到一个更大的值然后替代之前最大的值。是不是?对不对?放慢了时间,原来大脑也并不是一眼就看出来了其中的最大值。如果可以理解这个道理,那么也就明白语言的思路不过是模拟大脑的思维方式而已。而也许所有的事物到了最最本质,都在遵循一样的道理。就像是结绳记事一样,我们只是在通过自己的方式来认识这个世界吧。
再说到面向对象,就要说到它的三个基本特征:封装,继承,多态。
第一个基本特征:封装
其实封装的概念早在我们试图把所有的具体事物和问题都抽象为对象的那一刻就开始了。当java拥有了这么多对象,就好像小孩子有了各种各样的积木,这些对象之间就可以产生作用,互相配合来实现最后的目的。
而封装对于java来说的做法,就是类(class)。所有的对象都被以类的方式展示给我们。下面给出java的一个类,参照上文中给出的例子。
public class Car{ }
我们定义好了一个汽车类。其次要进一步描述,汽车拥有哪些属性呢?
比如说汽车有长、宽、高和颜色。怎么来描述呢?点像是画画,我不是在写代码,我是在画画,我们怎样画一个我们所认为的汽车?
public class Car{ int length; int width; int height; }
画好了它的基本属性,那么这个汽车能做什么呢?汽车能向前开,向后倒。
public class Car{ int length; int width; int height; public void goForward(){} public void goBackward(){} }
如此已经画好了一辆汽车。也就封装好了一辆汽车,这辆汽车就是java世界里的汽车,就好像在画里。
封装隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数据。对外界而已它的内部细节是隐藏的,暴露给外界的只是它的访问方法。
第二个基本特征:继承
封装好的对象已经可以作为java中的一个基本单元来工作了。但是试想这么一种情况,我现在又需要重新创建一个对象,卡车。
卡车作为汽车的一种,自然是拥有汽车类的所有的属性和方法。(经过上面的介绍,应该对于属性和方法这种说法并不陌生了)
那么我是否应该重新创建一个类呢。比如:
public class Truck{ int length; int width; int height; public void goForward(){} public void goBackward(){} }
是不是有些累赘,这也就是继承的作用。一个事物不会无缘无故被创造出来,存在就有其存在的意义。在java中当一个类继承另外一个类的时候,被继承的类成为父类,继承者称为子类。通过extends这个关键字来实现。代码如下:
public class Truck extends Car{ }
这种写法和上面直接定义Truck这个类的写法效果是一样的。卡车类已经拥有了关于汽车的公共属性。那么我们再来定义它所私有的方法。
比如说,卡车有载货量这个属性,卡车能够拉货:
public class Truck extends Car{ int burden; //载货量 public void pullThings(){} //载货 }
继承大大的减小了重复代码的书写量,减轻了系统运行的负担,同时又非常好维护,比如我们要给汽车再增加一个所有的汽车都拥有的共同属性,那么该怎么办?在使用继承之后,我们只需要给父类Car增加即可,那么所有的不管是卡车,还是小汽车,还是面包车都拥有了新增加的属性。就不必在一个类一个类的去添加了。是不是很方便?继承是为了重用父类代码。两个类若存在IS-A的关系就可以使用继承。
第三个基本特征:多态
多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。
比如你是一个酒神,对酒情有独钟。某日回家发现桌上有几个杯子里面都装了白酒,从外面看我们是不可能知道这是些什么酒,只有喝了之后才能够猜出来是何种酒。你一喝,这是剑南春、再喝这是五粮液、再喝这是酒鬼酒….在这里我们可以描述成如下:
酒 a = 剑南春
酒 b = 五粮液
酒 c = 酒鬼酒
这里所表现的的就是多态。剑南春、五粮液、酒鬼酒都是酒的子类,我们只是通过酒这一个父类就能够引用不同的子类,这就是多态:我们只有在运行的时候才会知道引用变量所指向的具体实例对象。
上一篇文章中有前辈给我提出了问题,在此感激不尽。
也感谢诸位能够关注点赞。扫描识别下面的二维码即可。