java零基础入门-面向对象篇(十二) 抽象类
抽象类这个玩意,理解起来费点劲。我们从字面意思开始吧。
抽象一词的本义是指人在认识思维活动中对事物表象因素的舍弃和对本质因素的抽取。说人话就是删除看的懂得,留下看不懂的。
应用于美术领域,便有了抽象性艺术、抽象主义、抽象派等概念。
来看一个著名的抽象派作品。
罗伯特-雷曼《无题》
84岁的美国艺术家罗伯特·雷曼1961年创作的油画《无题》,以折合人民币8000万至1.2亿元的价格拍卖。
我感觉这画跟我家卫生间的瓷砖有点像,莫非我家的还是个抽象派卫生间不成...
至于抽象类,它和抽象画还真的有点相似之处
抽象画:我告诉你我画了一幅画,具体画的啥,我也不知道!
抽象类:我告诉你我定义了一些方法,方法具体做什么,我也不知道!
为什么要抽象类
画家分为很多流派,以我浅显的艺术知识,大概分得清楚三个流派的画家,抽象派,印象派,立体派。
现在确定了父类 - 画家,然后三个子类 抽象派画家 , 印象派画家,立体派画家去继承画家这个类。画家类里面有一个方法,画画,这个方法是必须有的。
好了,问题出现了,当我们使用父类 - 画家创建对象,然后调用 画画这个方法的时候,它应该画出来的是哪个流派的画?
是不是懵圈了?你就给我个画家,也没问人家是哪一派的,就拉着人家画画,鬼知道他画的啥。
无法确定画画的流派
这说明一个什么问题?如果我们将某一部分事物的特征抽取出来,定义成了父类,其实这个父类是具有指导性的,而不是可实现性。
说人话,你非要将画家提出一个父类,那么就不要在父类里面实现方法,也就是不要在父类里面写代码逻辑。因为父类并不知道他自己被实例化以后,该如何实现方法。
比如这个画家,如果不是画家的子类,具体到某个流派的画家,在画家这个类里面实现画画这个方法是毫无意义的。他不知道该画个什么流派的画出来。我们只会使用子类重写的画画方法,而不会使用父类的画画方法。
画家的画画方法无人使用
有同学肯定有疑问,既然我们不使用父类里面的画画方法,删掉不就行了?只在子类里面写画画的方法不就行了?
那么我请问你,你见过连画画都不会的画家吗?画家这个类没有画画这个方法,就算代码不错,你的类的设计就是错的。类是对实际事物的抽象,这个是原则。
那该怎么做?
这时候就该抽象方法登场了。把画画这个方法定义成抽象方法,画家父类并不实现任何代码,而是留给子类去实现他。你是什么派的画家,画画的方法就画什么派的画就行了。
抽象类和抽象方法
看到了没有,抽象方法的核心思想就是 啥也不做~ 具体要做的,用子类去实现抽象方法即可。
抽象类的清规戒律
1.抽象方法不能被调用。
2.一个类被定义为抽象类以后,就不能使用new关键字新建对象了。
3.抽象类的子类必须重写抽象方法。
这三个规则放在一起,因为他们环环相扣。为了方便记忆,我们用代码来讲解。
首先看报错情况。
报错信息
1.因为抽象方法没有方法体,啥也不干,所以不能调用抽象方法,因为这样做毫无意义。
2.假设可以实例化抽象类,那么就可以用抽象类的对象去调用什么也干不了的抽象方法,这样违背了第一条原则。
3.如果继承了抽象类,而又不去重写(实现)抽象类的抽象方法,会发生什么?因为子类没有实现父类的抽象方法,那么用子类对象就可以调用到父类的抽象方法,这样也违背了第一条原则。
必须实现抽象方法
4.抽象类可以包含普通方法和构造器。抽象类就是专门用来被子类继承的,如果子类都有一个不必被重写的方法,那么可以将它定义在父类里面,每个子类都可以调用他。构造器也一样,可以被子类复用。
比如画家除了画画这个抽象方法以外,还可以有卖画这个方法,上面那位大师的一幅画可是卖了几千万。每个画家都可以卖画,自己不去实现,就调用父类的方法。构造器也是一样,可以用super调用抽象类的构造器,大家可以自己实现一下。
举个栗子
说了半天抽象类,下面再举个例子帮助大家更好的理解一下。
来来来,需求讲解一下,现在要做三个功能,请假,加班,外出,原型图如下。如果是你你会怎么做?
如果我们没有一点点的抽象能力,肯定会说,这还不简单,做三个功能呗。
但是我们现在可是学过抽象类的人了,怎么能做这么不优雅的事,我们必须要有设计的概念。
原型图
我们观察了原型图以后,可以看到,红色框中的内容,是三个功能都有的。不管你是请假,外出,还是加班,都需要一个人来对你的请求进行审批。这个是必须的(前面有个红色星星)。
而审批转聊天功能和抄送功能都是非必须的,可以不填。
再看蓝色框框,请假事由必须填,照片可以不填。
外出事由是必须填的,没事别乱跑,好好上班。
加班事由可以不填,叫你加班还需要理由么?
分析过后,我们总结一下,红色框里的是相同的功能可以提出来复用,而蓝色框是每个功能独有的。
我们看看用抽象类的高端玩家和不用抽象类的普通玩家是如何设计以上功能。
普通玩家
普通玩家设计了三个功能,自己体会。
高端玩家
高端玩家抽象了一个抽象父类,这样设计还有一个优点。如果像普通玩家一样设计三个独立的类,那么可能会漏掉功能,比如说在请假单里面,忘记写add_reason这个方法,这是有可能发生的。
而如果设计成子类继承抽象父类,则不会发生这种情况,因为抽象方法必须实现,不然就报错。这也是用抽象类来规范子类的一个好方法。
请好好理解本章内容,因为下一章,会介绍一个比抽象类更抽象的一个知识点,请做好准备。