抽象类 —— 半成品类
抽象类就像毛坯房:框架搭好了,但有些房间没装修,留给你来完成
用 abstract 关键字修饰,里面可以有”只声明不实现”的抽象方法
1 | // 抽象类:不能直接 new,必须有子类来实现 |
接口 —— 纯粹的契约
接口就像行业标准/规范:USB接口规定了形状和电压,但不管你内部怎么实现
用 interface 关键字定义,表示”你要具备这些能力”
1 | // 接口:定义一组能力规范 |
代码示例:抽象类和接口配合使用
1 | // 抽象类:提供基础骨架 |
1 |
|
Java 8 接口新特性
Java 8 之前接口只能有抽象方法,Java 8 开始接口变强了,加了两种新方法:
default 方法:有方法体,实现类可以直接用,也可以重写
为什么需要?假设一个接口已经有100个实现类了,你想给接口加个新方法,如果是抽象方法,100个类全得改。用 default 方法就不用,向下兼容
1 | public interface Collection { |
static 方法:接口自己的工具方法,通过 接口名.方法名() 调用
1 | public interface StringUtils { |
注意:default 方法可能导致”菱形继承”冲突
1 | interface A { default void hello() { System.out.println("A"); } } |
抽象类 vs 接口 对比表(必背)
| 特性 | 抽象类(abstract class) | 接口(interface) |
|---|---|---|
| 关键字 | abstract class |
interface |
| 能否有构造器 | ✅ 可以 | ❌ 不行 |
| 能否有普通字段 | ✅ 可以 | ❌ 只能有 public static final 常量 |
| 能否有普通方法 | ✅ 可以 | ✅ Java 8 起有 default 方法 |
| 能否有抽象方法 | ✅ 可以 | ✅ 默认就是抽象的 |
| 多继承 | ❌ 单继承(只能 extends 一个) | ✅ 多实现(可以 implements 多个) |
| 成员修饰符 | 四种都行(参见 访问修饰符) | 方法默认 public,字段默认 public static final |
| 设计意图 | “是什么”(is-a 关系) | “能做什么”(has-a 能力) |
一句话区分:
抽象类是模板——“你是我这类东西,按我的骨架来填”
接口是能力标签——“你能干这个事,具体怎么干你自己定”
什么时候用抽象类,什么时候用接口
用抽象类的场景:
子类之间有大量相同的代码逻辑需要复用
需要定义非 public 的成员(protected / private 字段或方法)
需要构造器来初始化状态
例子:AbstractList 是 ArrayList 和 LinkedList 的抽象父类,提供了很多公共实现
用接口的场景:
定义一种跨继承体系的能力(不相关的类都需要某个能力)
需要多实现(一个类要具备多种能力)
定义 API 契约,让不同团队独立开发
例子:Comparable(排序能力)、Serializable(序列化能力)、Runnable(可运行能力)
实际开发原则:能用接口就用接口,不够再考虑抽象类
实际场景举例
JDBC 接口 —— 接口最经典的应用
Java 定义了 Connection、Statement、ResultSet 等接口
MySQL 驱动实现这些接口 → MySQL 版本的 Connection
Oracle 驱动实现这些接口 → Oracle 版本的 Connection
你的代码面向接口编程,换数据库只换驱动包,代码不用改
1 | // 你写的代码:只依赖接口 |
Comparable 接口 —— 让对象能排序
1 | public class Student implements Comparable<Student> { |
常见坑
坑1:抽象类不能直接 new
1 | // Animal animal = new Animal(); // ❌ 编译报错!抽象类不能实例化 |
坑2:子类必须实现所有抽象方法,除非子类自己也是抽象类
1 | abstract class Shape { |
坑3:接口字段的陷阱
接口里写 int MAX = 100; 其实是 public static final int MAX = 100;
这是常量!赋值之后不能改
坑4:abstract 和 final 不能同时用
abstract 说”必须被重写”,final 说”不许被重写”,互相矛盾
同理 abstract 和 private 也冲突(private 方法子类看不到,怎么重写?)
练习题
题1:下面的代码能编译吗?
1 | interface Printable { |
答案:可以。因为 Document 自己是 abstract 的,不需要实现所有接口方法,留给子类
题2:一个类能同时继承一个抽象类并实现多个接口吗?
答案:可以。class Duck extends Animal implements Flyable, Swimmable
Java 不支持多继承类,但支持多实现接口,这就是接口的核心价值
题3:Java 8 之后接口能有方法体了,那抽象类还有存在的必要吗?
答案:有。抽象类能有构造器、能有普通字段(有状态)、成员能用 private/protected。接口虽然有了 default 方法但仍然不能有实例字段和构造器
| 上一章 | 目录 | 下一章 |
|---|---|---|
| 访问修饰符 | java基础 | 内部类与匿名类 |