共计 3020 个字符,预计需要花费 8 分钟才能阅读完成。
前言
抽象类、接口对于不论是 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 宝典