前言
抽象类、接口对于不论是Java、C++等程序猿都不生疏,但你晓得如何正确地应用抽象类和接口吗?你是否还在不置可否、只是简略记忆了两者的区别,遇到理论状况就不晓得如何抉择?
明天,我就来带你彻底弄清楚这俩的区别,当然,本文基于Java,然而对其余语言的程序猿一样实用,包会~
什么是抽象类?什么是接口?
这里关照刚入门的程序猿,简略介绍一下这俩的定义。
抽象类(abstract class):为了继承而存在。
接口(interface):比抽象类更形象的存在。
介绍的的确挺简略,但还是基本就不晓得怎么抉择他俩哪个啊……接着看!
抽象类和接口的区别
其实我也总结过两者的区别,如下:
抽象类:(1)形象办法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无奈实现该办法),缺省状况下默认为public。
(2)抽象类不能用来创建对象。
(3)如果一个类继承于一个抽象类,则子类必须实现父类的形象办法。如果子类没有实现父类的形象办法,则必须将子类也定义为abstract。
(4)抽象类的成员变量能够是任何类型的。
(5)能够有动态代码块和静态方法。
(6)一个类只能继承一个抽象类。
(7)类是“是不是关系”。
接口:
(1)变量只能定义为public static final。
(2)办法只能是形象的,没有办法体。
(3)不能有动态代码块和静态方法。
(4)一个类能够实现多个接口。
(5)接口是“有没有关系”。
(如果须要我自己整顿的一些笔记,能够关注公众号 养猪的程序猿,前面会分享)
当然,这些区别只实用Java8以前,Java8的接口能够有默认办法、静态方法,这些新个性会在上面介绍。
记住我列的这些区别,并且理解一些Java8新个性,那么面试这块应该没啥太大问题~~不过,面试官可能会让你举理论的例子或者给你个情景你来抉择,对于只会死记面试题的选手来说,可能就会有问题了。不过,别慌,上面我带你通过一个十分贴近生活的例子来让你彻底弄懂如何抉择!
如何抉择?
其实,下面的区别曾经有写到,抽象类是一种“是不是”的关系,而接口是“有没有”的关系。所以,很容易想到抽象类应该是一类事物的共有的特色,比方一个Person,他有眼睛、肤色,这些形容一个人的特色能够定义在抽象类中,而一个人的行为如打篮球,这些能够定义在接口中。
这个例子其实还是不太显著,我再以一个实在程序猿的例子,通过实战来讲话吧!
对于一个程序猿。一天的开始,必定得先起床,那么就要保护一个变量——起床工夫,因为每个人的起床工夫都是不同的,是一个状态量,所以这个起床工夫不能用final润饰,所以接口就pass了,只有用抽象类保护这个变量。
而后去下班打卡,能够用一个函数形容打卡。下班打卡我这里就假如每个公司都要求吧hh(当然我呆过的公司有的是弹性的,不必上下班打卡hh),所以这是每个程序猿的共性,应该也放在抽象类保护。
程序猿的生存必定不能只有写代码,能够有一些兴趣爱好,比方打球,但也不是每个程序猿都喜爱打球(宅在工位摸鱼hh),所以很容易判断应该抉择接口来保护打球这个趣味。
到这里,咱们把代码写一下:
//程序猿基类public abstract class BaseWorker { //起床工夫 protected int wakeupTime = 7; //下班打卡 protected abstract void clockIn(); }
用protected润饰次要是为了继承,让子类能拜访。
public interface Interest { void playBall();}//一只程序猿public class Worker extends BaseWorker implements Interest { protected int wakeupTime = 6; @Override protected void clockIn() { //…… } @Override public void playBall() { //…… } }
然而,我要通知你,抽象类和接口的抉择也不是规定死的,要依据业务来正当调整。比方,咱们公司基本上每个人都喜爱打球,那么如果还是把打球趣味定义在接口里的话,咱们每次都要implements这个接口,代码量冗余大。所以,这种状况咱们能够把打球归属到一个新的worker抽象类中,能够缩小implements的书写量。
代码批改如下:
//程序猿都爱打球public class WorkerLikeBall extends BaseWorker{ protected abstract void playBall();}
这样,就只须要继承BaseWorker拿到起床工夫和下班打卡即可。外表上看不合乎我后面说的抽象类的标准,然而这样写更合乎咱们的诉求,只有灵活运用能力写出简略高效的代码。
接口的默认办法和静态方法
看完下面我讲的,置信你曾经学会如何去抉择了~最初,咱们聊聊接口的默认办法和静态方法,这俩办法是Java8的新个性。
Java8能够在接口里写静态方法,比方新版的Comparator,增加了static办法comparing,传个function型接口即可。
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);int min = list.stream().min(Comparator.comparing(value -> value)).get();int max = list.stream().max(Comparator.comparing(value -> value)).get();
也能够在本人的接口减少静态方法,不会影响到原代码的应用(不必在实现类重写这个办法)。
public interface Interest { void playBall(); default void start() { System.out.println("start playing"); } static void time() { System.out.println( LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_TIME) ); } }
默认办法,用default润饰,实现类能够不实现默认办法,如果子类实现了,那就用子类实现的默认办法。默认办法的外围之处就是兼容以前的代码,易于扩大。
默认办法的多继承问题:如果实现类实现了多个接口,而且每个接口都有同名的默认办法,那么Java无奈判断应用哪个,这时,在实现类重写这个办法即可,因为重写优先级最高。
静态方法只会通过接口的名称去调用,所以不会呈现多继承问题。
那么就会有小伙伴问了,Java8的接口这么强了还要抽象类干嘛呢?
还是那句话,存在即正当。
首先,Java8减少默认办法的最后的设计目标是在改变接口的根底上,不改变其余实现类。
比方Java的List接口,在Java8减少了默认办法sort,这样其余实现List接口的类不必去批改也能继承到这个办法来应用,毕竟当初函数式接口这么炽热,必定会减少更多更强的默认办法到接口中的。
然而对于状态类的变量,还是须要放在抽象类中的。
关注公众号:java宝典