持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第12天,点击查看活动详情
Java是面向对象的语言,它的三大特性是封装,继承,多态。多态有接口多态和类多态,由于抽象类与接口中都有抽象方法,经常被拿来对比,所以接口和抽象类的区别成了面试中的高频问题。常规性的区别不做讨论,只从使用的角度出发去挖掘区别。
抽象类
下图中我们把方块当成类,把圆形当成属性或者方法。如图所示三个类拥有共同的属性跟方法(粉色圆圈与红色圆圈),这个时候为了代码复用,通常的做法是将公共的部分提取出来。这个时候问题就来了,父类中的方法实现,是实现成蓝色,紫色还是灰色?
答案是实现成啥颜色都不合适!解决办法就是不实现(如下图),没有实现的方法在Java中叫抽象方法,那么含有抽象方法的类称为抽象类。抽象类从用的的角度来说就是为了代码复用。
另外大家知道为什么抽象类不能直接new吗?如果可以直接new,那么调用到下方白色圈的时候怎么办呢?多问一个为什么总没有坏处。
接口
下图中一共有7种自行车,从1到7是不断进步的过程。这些自行车是有一些共同的属性的,两个轮子,一个坐垫等。它们也有不同的地方,有的驱动是前轮驱动,有的是后轮驱动,有的是两轮驱动,有的可以变速,有的不能变速,有的适合平路,有的适合山路,有的适合爬坡有的不适合爬坡。
如果把这些不同的行为也用图形的形式体现出来(见下图)那么这个时候我们能把这些不同的地方提取出来吗? 答案是不能,看个图大家就知道合适不合适了。第一眼过去感觉就不对。这么处理是有问题的?这个时候会发现每个子类中都会出现用不到其他子类的两个方法。那么这种设计就是有问题的,向上抽取的行为应该都是三个类共有的才是正常的复用。
假设用是十字架,五角星,云朵三个形状表示三种不同的行为。那么这个时候将子类的这些方法都放到父类是不合适的,这样每个子类就从父类哪里继承了两个没有用的行为。所以,父类就只抽取相同行为的属性与方法。至于不同的让子类自己去扩展就好了,Java中扩展单个方法时,实现某个接口即可。
总结
看完上面两部分大家大概能感觉到接口与抽象类在使用场景上的区别,但是总感觉就是差了那么点意思。总结一下。
接口最大的优点就是避免了多继承的复杂性(A extends B,B extends C),它可以多实现(A implements D,E)。抽象类和接口都可以让一些功能最大程度上得到复用,由于设计的出发点不同,两者的使用场景也就不同。绕一点就是抽象类是给同行使用的,接口是给外行使用的。
现在回头看抽象类和接口的区别,你就会明白Java中为什么类只能单继承,而接口可以多实现!