谈谈接口和抽象类有什么区别?
典型回答
- 接口和抽象类是 Java 面向对象设计的两个基础机制。
- 接口
- 接口是对行为的抽象,它是抽象方法的集合,利用接口可以达到 API 定义和实现分离的目的。
- 接口,不能实例化;
- 不能包含任何非常量成员,任何 field 都是隐含着 public static final 的意义;
- 同时,没有非静态方法实现,也就是说要么是抽象方法,要么是静态方法。
- 抽象类
- 抽象类是不能实例化的类,用 abstract 关键字修饰 class,其目的主要是代码重用。
- 除了不能实例化,形式上和一般的 Java 类并没有太大区别,可以有一个或者多个抽象方法,也可以没有抽象方法。
- 抽象类大多用于抽取相关 Java 类的共用方法实现或者是共同成员变量,然后通过继承的方式达到代码复用的目的。
- 接口
- Java 类实现 interface 使用 implements 关键词,继承 abstract class 则是使用 extends 关键词。
考点分析
- 如果面试官稍微深入一些,可以从不同角度全面地考察你对基本机制的理解和掌握。
- 对于 Java 的基本元素的语法是否理解准确。
- 能否定义出语法基本正确的接口、抽象类或者相关继承实现,涉及重载(Overload)、重写(Override)更是有各种不同的题目。
- 在软件设计开发中妥善地使用接口和抽象类。
- 你至少知道典型应用场景,掌握基础类库重要接口的使用;
- 掌握设计方法,能够在 review 代码的时候看出明显的不利于未来维护的设计。
- 掌握 Java 语言特性演进。
- 现在非常多的框架已经是基于 Java 8,并逐渐支持更新版本,掌握相关语法,理解设计目的是很有必要的。
- 对于 Java 的基本元素的语法是否理解准确。
知识扩展
- 面向对象设计
- 封装
- 封装的目的是隐藏事务内部的实现细节,以便提高安全性和简化编程。
- 封装提供了合理的边界,避免外部调用者接触到内部的细节。
- 从另外一个角度看,封装这种隐藏,也提供了简化的界面,避免太多无意义的细节浪费调用者的精力。
- 继承
- 继承是代码复用的基础机制,可以看作是非常紧耦合的一种关系,父类代码修改,子类行为也会变动。
- 在实践中,过度滥用继承,可能会起到反效果。
- 多态
- 你可能立即会想到重写(override)和重载(overload)、向上转型。
- 简单说,重写是父子类中相同名字和参数的方法,不同的实现;
- 重载则是相同名字的方法,但是不同的参数,本质上这些方法签名是不一样的。
- 封装
- 基本的 S.O.L.I.D 设计原则
- 单一职责(Single Responsibility)
- 类或者对象最好是只有单一职责,在程序设计中如果
发现某个类承担着多种义务,可以考虑进行拆分。
- 类或者对象最好是只有单一职责,在程序设计中如果
- 开关原则(Open-Close, Open for extension, close for modification)
- 设计要对扩展开放,对修改关闭。
- 换句话说,程序设计应保证平滑的扩展性,尽量避免因为新增同类功能而修改已有实现,这样可以少产出些回归(regression)问题。
- 里氏替换(Liskov Substitution)
- 这是面向对象的基本要素之⼀,进行继承关系抽象时,
凡是可以用父类或者基类的地方,都可以用子类替换。
- 这是面向对象的基本要素之⼀,进行继承关系抽象时,
- 接口分离(Interface Segregation)
- 我们在进行类和接口设计时,如果在一个接口里定义了太多方法,其子类很可能面临两难,就是只有部分方法对它是有意义的,这就破坏了程序的内聚性。
- 对于这种情况,可以通过拆分成功能单一的多个接口,将行为进行解耦。
- 依赖反转(Dependency Inversion)
- 实体应该依赖于抽象而不是实现。
- 也就是说高层次模块,不应该依赖于低层次模块,而是应该基于抽象。
- 实践这一原则是保证产品代码之间适当耦合度的法宝。
- 单一职责(Single Responsibility)