🗒️抽象类和接口的对比
2017-9-13
| 2024-8-22
字数 1956阅读时长 5 分钟
type
status
date
slug
summary
tags
category
icon
password
comment
update_time
Aug 22, 2024 06:42 AM
create_time
Aug 22, 2024 06:20 AM

抽象类 —— 一种模板式设计

  • 抽象类就是为了继承而存在
  1. 抽象类不能被实例化,实例化 交由它的子类完成,它只需要有一个引用即可。
  1. 抽象方法由子类来进行重写。必须为 public 或者 protected,缺省情况下默认为 public
  1. 只要包含一个抽象方法的抽象类,该方法必须要定义成抽象类,不管是否还包含有其他方法。
  1. 抽象类中可以包含具体的方法,当然也可以不包含抽象方法。
  1. abstract 不能与 final 并列修饰同一个类。
  1. abstract 不能与 privatestaticfinal 或 native 并列修饰同一个方法。
  • 抽象类的意义在于:
  1. 为其子类提供一个公共的父类型,避免该类被实例化;
  1. 封装子类中的重复内容(成员变量和方法);
  1. 定义公共抽象方法,由子类提供不同的实现。

接口 —— 一种辐射式设计 (一种行为规范)

  • 接口 本身也是类
  • 变量 被隐式地指定为 public static final (只能是 public static final 变量,用 private 或 private 修饰会报编译错误)
  • 方法【必须都抽象方法】 被隐式地指定为 public abstract (只能是 public abstract 方法)
  • 接口中所有的方法不能有具体的实现(jdk1.8 中可以有 default 方法和 static 方法)
接口是一种极度抽象的类型,比抽象类更加 “抽象”,并且一般情况下不在接口中定义变量(如果定义只能是 Static Final)

对比 ——

语法层面上的区别
1)抽象类可以提供成员方法的实现细节,而接口中只能存在 public abstract 方法;
2)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的;
3)接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;
4)一个类只能继承一个抽象类,而一个类却可以实现多个接口
设计层面上的区别
  1. 什么是模板式设计?例子:用模板 A 设计了 ppt B 和 ppt C,ppt B 和 ppt C 公共的部分就是模板 A,如果公共部分需要改动,则只需要改动模板 A 就可以了,不需要重新对 ppt B 和 ppt C 进行改动
  1. 什么是辐射式设计?比如某个电梯都装了某种报警器,一旦要更新报警器,就必须全部更新。
抽象类是自底向上抽象而来的,接口是自顶向下设计出来的
  • 对于抽象类,如果需要添加新的方法,可以直接在抽象类中添加具体的实现,子类可以不进行变更;
  • 而对于接口则不行,如果接口进行了变更,则所有实现这个接口的类都必须进行相应的改动。

抽象类和接口的对比

参数
抽象类
接口
默认的方法实现
它可以有默认的方法实现
接口完全是抽象的。它根本不存在方法的实现
实现
子类使用 extends 关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有有方法体的方法的实现。
子类使用关键字 implements 来实现接口。它需要提供接口中所有声明的方法的实现
构造器
抽象类可以有构造器
接口不能有构造器
与正常 Java 类的区别
除了你不能实例化抽象类之外,它和普通 Java 类没有任何区别
接口是完全不同的类型
访问修饰符
抽象方法可以有 publicprotected 和 default 这些修饰符
接口方法默认修饰符是 public。你不可以使用其它修饰符。
main 方法
抽象方法可以有 main 方法并且我们可以运行它
接口没有 main 方法,因此我们不能运行它。
多继承
抽象方法可以继承一个类和实现多个接口
接口只可以继承一个或多个其它接口
速度
它比接口速度要快
接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。
添加新方法
如果你往抽象类中添加新的方法,可以提供默认的实现。因此你不需要改变你现在的代码。
如果你往接口中添加方法,那么你必须改变实现该接口的类。

什么时候使用抽象类和接口

  • 如果你拥有一些方法并且想让它们中的一些有默认实现,那么使用抽象类吧。
  • 如果你想实现多重继承,那么你必须使用接口。由于 Java 不支持多继承,子类不能够继承多个类,但可以实现多个接口。因此你就可以使用接口来解决它。
  • 如果基本功能在不断改变,那么就需要使用抽象类。如果不断改变基本功能并且使用接口,那么就需要改变所有实现了该接口的类。

实例 ——

门和警报的例子:门都有 open () 和 close () 两个动作,此时我们可以定义通过抽象类和接口来定义这个抽象概念:
或者:
这种方法违反了面向对象设计中的一个核心原则 ISP (Interface Segregation Principle)【见批注】,在 Door 的定义中把 Door 概念本身固有的行为方法和另外一个概念 "报警器" 的行为方 法混在了一起。这样引起的一个问题是那些仅仅依赖于 Door 这个概念的模块会因为 "报警器" 这个概念的改变而改变,反之依然。
Door 的 open () 、close () 和 alarm () 根本就属于两个不同范畴内的行为,open () 和 close () 属于门本身固有的行为特性,而 alarm () 属于延伸的附加行为。因此最好的解决办法是单独将报警设计为一个接口,包含 alarm () 行为,Door 设计为单独的一个抽象类,包含 open 和 close 两种行为。再设计一个报警门继承 Door 类和实现 Alarm 接口。
批注:
 ISP(Interface Segregation Principle 接口分离原则):面向对象的一个核心原则。它表明使用多个专门的接口比使用单一的总接口要好。
 
一个类对另外一个类的依赖性应当是建立在最小的接口上的。
 
一个接口代表一个角色,不应当将不同的角色都交给一个接口。没有关系的接口合并在一起,形成一个臃肿的大接口,这是对角色和接口的污染。
 
  • Java
  • weex-eros+vue Android 拍照并预览图片踩坑【小白向】JVM 如何管理内存
    Loading...