《Java 100 天进阶之路》第18篇:Java接口和抽象类的异同,default关键字
第18篇:Java接口和抽象类的异同,default关键字
📌 系列导航:《Java 100 天进阶之路》完整目录 |
⬅️ 上一篇:第17篇:Java常用包装类与自动装箱拆箱深入|
➡️ 下一篇:第19篇:Java接口的作用和意义
一、核心知识点
- 接口(interface)和抽象类(abstract class)的定义与语法
- 相同点:都不能实例化,都可以包含抽象方法
- 不同点:
- 抽象类可以有状态(成员变量)、构造方法、具体方法;接口早期只能有常量(
public static final)和抽象方法(Java 8 后可以有default/static方法,Java 9 可以有private方法) - 一个类只能继承一个抽象类(单继承),但可以实现多个接口
- 抽象类成员的访问修饰符任意;接口方法默认
public,变量默认public static final - 抽象类是
is-a关系,接口是can-do关系(能力)
- 抽象类可以有状态(成员变量)、构造方法、具体方法;接口早期只能有常量(
default关键字:Java 8 引入,接口中可以提供默认实现,子类可重写也可不重写,用于接口演进- 设计选择原则:优先使用接口(多实现),需要共享状态或通用行为时使用抽象类
二、通俗讲解(1分钟开心学)
1. 抽象类——不完整的类
抽象类就像一张“半成品图纸”,它定义了一些通用属性和方法,但某些关键步骤留空,等着子类去填充。
- 可以有构造方法(被子类调用)
- 可以有自己的成员变量(不是常量)
- 可以有普通方法(有方法体)
- 用
abstract修饰的方法没有方法体,必须由子类实现
2. 接口——纯粹的能力规范
接口是一份“合同”或“能力证书”,它只告诉你“你能做什么”,不告诉你“怎么做”。
- 完全没有状态(不能有实例变量,只能有静态常量)
- 方法默认是
public abstract(Java 8 之前) - 一个类可以实现多个接口(多继承的替代方案)
生活类比:
抽象类就像“汽车设计图纸”:它画好了底盘、方向盘、刹车的位置,但引擎具体用哪种、轮胎尺寸多少,留给你决定。
接口就像“可飞行资质”:只要你能飞,不管你是鸟、飞机还是超人,都算。你不需要继承“飞行器”类,只需要实现“飞行”接口。
3. default 方法——接口的“救生圈”
Java 8 之前,接口一旦发布,就不能再添加新方法,否则所有实现类都要被迫修改。default 方法允许给接口添加新方法并提供默认实现,实现类可以不改,也可以重写。
4. 如何选择?
- 当你需要定义 “是什么” (is-a)且需要共享代码时,用抽象类
- 当你需要定义 “能做什么” (can-do)且可能有多种不相关的实现时,用接口
- 实际工程中常常 “接口 + 抽象基类” 搭配使用(如
List接口 +AbstractList抽象类)
三、实操代码案例 + 场景说明
场景:设计一个游戏中的角色系统。所有角色都有生命值(共享状态),并且部分角色可以飞行(能力)。
1. 抽象类示例(共享状态 + 通用方法)
abstract class GameCharacter {
protected String name;
protected int hp;
public GameCharacter(String name, int hp) {
this.name = name;
this.hp = hp;
}
// 抽象方法:不同角色攻击方式不同
public abstract void attack();
// 普通方法:所有角色通用
public void takeDamage(int damage) {
hp -= damage;
System.out.println(name + " 受到 " + damage + " 伤害,剩余生命 " + hp);
}
}
class Warrior extends GameCharacter {
public Warrior(String name) { super(name, 100); }
@Override
public void attack() {
System.out.println(name + " 用剑攻击!");
}
}
2. 接口示例(能力)+ default 方法
interface Flyable {
void fly(); // 抽象方法
// default 方法:提供默认实现,实现类可以不重写
default void takeOff() {
System.out.println("准备起飞...");
}
}
class Bird extends GameCharacter implements Flyable {
public Bird(String name) { super(name, 50); }
@Override
public void attack() { System.out.println(name + " 啄击!"); }
@Override
public void fly() { System.out.println(name + " 拍翅膀飞翔"); }
// takeOff() 可以直接使用 default 实现
}
class Plane implements Flyable {
@Override
public void fly() { System.out.println("引擎推动飞行"); }
// 也可以重写 takeOff
@Override
public void takeOff() {
System.out.println("滑行加速,拉起机头");
}
}
3. 接口与抽象类的异同比对表
| 特性 | 抽象类 | 接口(Java 8+) |
|---|---|---|
| 实例化 | 不能 | 不能 |
| 成员变量 | 可以是任意类型 | 只能是 public static final |
| 构造方法 | 可以有 | 不能有 |
| 继承/实现 | 单继承 | 多实现 |
| 访问修饰符 | 任意 | 方法默认 public(Java 9 允许 private 方法) |
| 非抽象方法 | 可以有普通方法 | 通过 default / static / private 提供 |
四、避坑要点
| 错误/误区 | 后果 | 正确做法 |
|---|---|---|
抽象类的构造方法写成 public |
虽能编译,但只能被子类调用,单独 new 会报错 |
通常用 protected,更语义化 |
| 接口中定义成员变量(非常量) | 编译错误 | 需要共享数据,用抽象类 |
两个接口有同名的 default 方法 |
实现类必须重写解决冲突 | 在实现类中重写,并可用 InterfaceName.super.method() 指定 |
认为 default 方法可以被静态调用 |
编译错误 | default 方法只能通过实例调用 |
五、面试高频考点
Q1:抽象类和接口的区别(至少5点)?
- 抽象类有构造方法,接口没有。2. 抽象类可以有非
final成员变量,接口只能是常量。3. 抽象类方法可以用各种修饰符,接口方法默认public。4. 类单继承抽象类,多实现接口。5. 抽象类用于is-a,接口用于can-do。
Q2:为什么 Java 8 要引入 default 方法?
为了在保持向后兼容的前提下给现有接口增加新方法(如
Collection.stream()),避免所有实现类被迫修改。
Q3:一个类实现两个接口都有同名的 default 方法,怎么办?
必须在该类中重写该方法。可以调用其中一个父接口的默认方法:
Interface1.super.method()。
六、练习题
- 设计:定义抽象类
Vehicle(属性:品牌、速度,抽象方法:run()),接口Electric(方法:charge())。创建ElectricCar类继承Vehicle并实现Electric。 - 代码分析:为什么接口中的变量默认是
public static final?如果试图修改会怎样? - 动手:写两个接口
A和B,都有default void test(),然后写一个类实现两者,重写test()并分别调用两个父接口的默认方法。
📊 你的学习进度
- 当前:第18篇 / 共44篇 · 第二阶段:核心语法与面向对象(第5~20篇)
- ✅ 已完成:第1~17篇
- 📖 正在学:第18篇
- ⏳ 待学习:第19~44篇
👉 📚 完整目录 & 学习指南 | 🔥 订阅本专栏,不错过每一篇
💡 本专栏每篇都包含:避坑表 + 面试高频考点 + 练习题。每天30分钟,100天拿offer!
👉 下一篇预告
《Java接口的作用和意义》
内容简介:接口的解耦、多态、扩展性、标准化作用,面向接口编程,在框架中的应用。
💡 学完这篇,你将真正理解“面向接口编程”的含义,写出更灵活的代码。
📌 《Java 100 天进阶之路 | 从入门到上岗就业》 每天一篇,建议收藏 + 关注,一起100天拿offer!
👉 点击关注我,更新后第一时间收到推送!
更多推荐



所有评论(0)