Java 中的接口和抽象类之间的对比

一、接口

Interface,将其翻译成插座可能就更好理解了。我们通常利用接口来定义实现类的行为,当你将插座上连接笔记本的三角插头拔掉,换成微波炉插上去的时候,你就会发现,这两样东西它都是三角插头的。那么这个三角插头就可以视为一种规则,而这两样电器就是两个实现了同样规则的构件了。因为实现了同样的规则,使得动态地将一个构件换成另外一个构件变得容易得多。那么在代码中也是相同地道理,当两个类实现了相同的接口,将客户端中原有实现类换成另外一个,就变得简单不过了。

首先,定义一个接口的代码如下:

[public] interface InterfaceName {

    void fun1();

}

接口中可以拥有变量和方法,但是接口中定义的变量会被隐式默认为 public static final 变量,并且也只能是这样,如果你使用其他的修饰符修饰,编译时会报错。同样的,方法也会默认被 public abstract 修饰。但是,你只能定义一个方法,而不能有方法的实现类,接口中的方法只能是抽象方法,这一点就和抽象类不同了(抽象类可以有方法实现)。

而接口对应实现类的实例代码如下

public class ClassName implements InterfaceName, OtherInterface, [...] {

    public void fun1() {
// do something ...
} }

在 Java 中,类是单继承的,但是却可以继承多个接口,而接口可以继承多个接口。

二、抽象类

在 Java 语言中,类有两种:一种是具体类,另一种是抽象类。具体类可以实例化,抽象类不可以实例化。所以在这里可以想到,抽象类创建出来,就是用来被继承的,毕竟你不能用一个无法实例化的类来为你完成什么功能(当然这里不包括静态变量和方法的调用,但是如果只是用来做这些,那你为什么要把这个类声明为抽象类呢?)

在了解抽象类之前,我们先了解抽象方法:抽象方法是一种特殊的方法,它只有声明,而没有具体的实现:

abstract void fun1();

在抽类中的定义的抽象方法必须使用 absract 关键字修饰,同样抽象类也需要被 abstract 关键字修饰

[public] abstract class AbstractClassName {

    abstract void fun1();

}

如果一个类继承了抽象类,那么子类就必须要实现抽象类中定义的所有抽象方法,除非将子类也定义为抽象类。

三、对比

语法功能上的对比

  • 接口只能包含抽象方法,而抽象类即可有普通方法,也能有抽象方法
  • 接口不包含构造方法,抽象类中可以包含构造方法以备继承类扩充
  • 接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法
  • 接口只能定义静态常量属性,抽象类既可以定义普通属性,也可以定义静态常量属性

设计思想上的对比

我们口头上常说:实现一个接口,继承一个抽象类。其实这句话就已经将接口和抽象类之间的区别表现出来了。

接口更多的是被视为一种契约,契约里的方法是让你来实现的。当别人给定你一个接口,你就按接口中定义的方法去实现,那么就是在实现一份契约了。所以接口是其实是一些方法特征的集合,这些方法特征当然来自于具体方法,但是它们一般都是来自于一些在系统中不断出现的方法。一个接口只有方法的特征,而没有方法的实现,因此这些方法在不同的地方被实现的时候,可以具有不同的行为。

而抽象类更多的是被视为一个模板,它提供的是一个继承的出发点,是子类中的共有部分的集中实现。所以抽象类是一种模板式的设计,什么是模板式设计?最简单例子,大家都用过 ppt 里面的模板,如果用模板A设计了 ppt B和 ppt C,ppt B 和 ppt C 公共的部分就是模板A了,如果它们的公共部分需要改动,则只需要改动模板A就可以了,不需要重新对 ppt B 和 ppt C 进行改动。也就是说对于抽象类,如果需要添加新的方法,可以直接在抽象类中添加具体的实现,子类可以不进行变更;而对于接口则不行,如果接口进行了变更,则所有实现这个接口的类都必须进行相应的改动。

四、继承复用与规范实现之间的选择

接口是一种特殊的抽象类,那么在开发中,何时选用接口?何时选用抽象类呢?

  • 优先选用接口

满足以下全部条件时,选用抽象类

  • 子类是父类的一个特殊类,而不是父类的一个角色,也就是要区分 “Has-A” 与 “Is-A” 两种关系的不同。Has-A 关系应当使用聚合关系描述,而只有 Is-A 关系才符合继承关系。

  • 不会出现需要将子类换成另外一个类的子类的情况

  • 子类具有扩展父类的责任。而不是具有置换掉(Override)或注销掉(Nullify)父类的责任。如果子类需要大量地置换掉父类的行为,那么这个子类就不应当成为这个父类的子类。

  • 只有父类和子类属于同一种分类的时候,才可以使用继承,不要从工具类继承。

五、Java 8 的新特性

从 Java 8 开始,接口也可以拥有默认的方法实现,这是因为不支持默认方法的接口的维护成本太高了。在 Java 8 之前,如果一个接口想要添加新的方法,那么要修改所有实现了该接口的类。

public interface InterfaceExample {

    void func1();

    default void func2(){
System.out.println("func2");
} }
public class InterfaceImplementExample implements InterfaceExample {
@Override
public void func1() {
System.out.println("func1");
}
}
public static void main(String[] args) {
InterfaceExample example = new InterfaceImplementExample();
example.fun1();
example.fun2();
}

六、参考

最新文章

  1. css基础知识点
  2. [JavaWeb 用MyEclipse分别创建最简单的JSP程序和Servlet程序]
  3. pthread 学习系列 case1-- 共享进程数据 VS 进程
  4. 关于adb驱动
  5. 2) LINQ编程技术内幕--yield return
  6. android 使用String.format("%.2f",67.876)自已定义语言(俄语、西班牙语)会把小数点变为逗号
  7. 【剑指offer】二叉树深度
  8. Android手机APN设置(中国移动 联通3G 电信天翼),解决不能上网的问题
  9. [转]IOS Segment页面之间view的切换
  10. javaweb学习路之三--websocket多人在线聊天
  11. VS2010下C/C++连接MySql数据库的方法
  12. .net大型分布式电子商务架构说明(转载来自<头条>)
  13. hdu 5536 xor题
  14. NDK开发,如何配置 debug环境
  15. java的几种引用之二
  16. Enterprise Architect 时序图
  17. BZOJ2480 Spoj3105 Mod 数论 扩展BSGS
  18. 大数据技术之_08_Hive学习_04_压缩和存储(Hive高级)+ 企业级调优(Hive优化)
  19. Storm中关于Topology的设计
  20. JavaScript oop proto与prototype原型图

热门文章

  1. 【解决】OCI runtime exec failed......executable file not found in $PATH": unknown
  2. Codeforces-527c
  3. k8s 开船记-修船:改 readinessProbe ,去 DaemonSet ,上 Autoscaler
  4. django学习01-建project和app
  5. 【MySQL】ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
  6. Mybatis-plus入门教程(一)
  7. 12个超好用的IntelliJ IDEA 插件!你用过几个?
  8. html5-心跳
  9. CouchDB学习一
  10. 现代前端库开发指南系列(二):使用 webpack 构建一个库