第一章:理解抽象的本质——为什么需要抽象类?
1.1 从具体到抽象的演进
场景:开发图形绘制系统,需要处理多种形状(圆形、矩形、三角形)
初级实现(问题:重复代码):
class Circle {
void draw() { System.out.println("绘制圆形"); }
double area() { return 0; } // 需要具体计算
}
class Rectangle {
void draw() { System.out.println("绘制矩形"); }
double area() { return 0; }
}
进阶实现(引入抽象类):
abstract class Shape {
// 抽象方法:无实现,强制子类完成
abstract void draw();
abstract double area();
// 具体方法:公共逻辑
void printInfo() {
System.out.println("面积:" + area());
}
}
class Circle extends Shape {
double radius;
@Override
void draw() { System.out.println("⚪"); }
@Override
double area() { return Math.PI * radius * radius; }
}
1.2 抽象类的核心特性
- 无法实例化:
new Shape()
会编译错误 - 可包含混合成员:抽象方法(必须实现) + 具体方法(直接继承)
- 构造方法存在:供子类初始化父类状态
abstract class Animal {
String name;
public Animal(String name) { this.name = name; }
abstract void makeSound();
}
class Dog extends Animal {
public Dog(String name) { super(name); }
@Override
void makeSound() { System.out.println(name + ":汪汪!"); }
}
1.3 抽象类的设计原则
- 模板方法模式:定义算法骨架
abstract class Game { // 具体方法定义流程 final void play() { initialize(); startPlay(); endPlay(); } abstract void initialize(); abstract void startPlay(); abstract void endPlay(); } class Chess extends Game { void initialize() { System.out.println("摆棋盘"); } void startPlay() { System.out.println("开始对弈"); } void endPlay() { System.out.println("收拾棋子"); } }
第二章:接口——行为的契约
2.1 接口的诞生背景
需求:实现会飞的鸟和会飞的飞机,但飞行方式不同
传统继承的局限:
// 错误的多重继承尝试 class Bird extends Animal, Flyable { ... } // Java不支持
接口解决方案:
interface Flyable { void fly(); // 默认public abstract } class Bird extends Animal implements Flyable { public void fly() { System.out.println("振翅高飞"); } } class Airplane implements Flyable { public void fly() { System.out.println("引擎推进"); } }
2.2 接口的现代进化(Java 8+)
默认方法:解决接口升级问题
interface USB { default void connect() { System.out.println("USB设备已连接"); } void transferData(); } class FlashDrive implements USB { public void transferData() { System.out.println("传输文件..."); } // 自动继承connect() }
静态方法:工具方法聚合
interface MathUtils { static int max(int a, int b) { return a > b ? a : b; } } // 使用:MathUtils.max(5,3)
2.3 接口的多继承威力
interface Swimmable {
void swim();
}
interface Diving extends Swimmable {
void deepDive();
}
class Penguin extends Bird implements Diving {
public void swim() { System.out.println("企鹅划水"); }
public void deepDive() { System.out.println("潜入深海"); }
}
第三章:抽象类 vs 接口——如何正确选择?
3.1 概念对比表
特性 | 抽象类 | 接口 |
---|---|---|
实例化 | 不能 | 不能 |
方法实现 | 可包含具体方法 | Java 8+支持默认方法 |
变量 | 任意类型 | 默认public static final |
构造方法 | 有 | 无 |
继承方式 | 单继承 | 多实现 |
设计目的 | 代码复用(IS-A关系) | 定义行为(CAN-DO关系) |
3.2 典型应用场景
抽象类适用场景:
- 多个相关类共享代码
- 需要定义非public成员
- 需要定义子类的公共状态
接口适用场景:
- 定义跨继承树的行为
- 需要多重继承
- 定义API契约
3.3 混合使用案例
abstract class Animal {
String name;
public Animal(String name) { this.name = name; }
abstract void eat();
}
interface Swimmable {
void swim();
}
class Dolphin extends Animal implements Swimmable {
public Dolphin() { super("海豚"); }
@Override
void eat() { System.out.println("吃鱼"); }
@Override
public void swim() { System.out.println("优雅游动"); }
}
第四章:深入接口内部——从字节码看本质
4.1 接口的编译产物
源代码:
interface Logger {
void log(String message);
default void debug(String msg) {
System.out.println("[DEBUG] " + msg);
}
}
反编译结果:
public interface Logger {
public abstract void log(String message);
public void debug(String msg) { /* 默认实现 */ }
}
4.2 默认方法的冲突解决
规则:
- 类中的方法优先级最高
- 子接口覆盖父接口
- 必须显式解决冲突
示例:
interface A {
default void show() { System.out.println("A"); }
}
interface B {
default void show() { System.out.println("B"); }
}
class C implements A, B {
// 必须重写
@Override
public void show() {
A.super.show(); // 明确调用A的实现
}
}
第五章:实战演练——电商系统设计
5.1 需求分析
- 商品分类:电子产品(保修期)、服饰(尺寸)
- 支付方式:信用卡、支付宝
- 物流服务:标准、加急
5.2 类图设计
<<abstract>>
Product
+ name: String
+ price: double
+ description(): void
▲
|
+------+-------+
| |
Electronics Clothing
▲ ▲
| |
+------+------+ +---+---+
| | | |
Laptop Phone TShirt Dress
<<interface>>
Payable
+ pay(): boolean
<<interface>>
Shippable
+ ship(): void
5.3 完整代码实现
// 抽象商品类
abstract class Product {
String name;
double price;
public Product(String name, double price) {
this.name = name;
this.price = price;
}
abstract void description();
}
// 电子产品子类
class Electronics extends Product {
int warrantyMonths;
public Electronics(String name, double price, int warranty) {
super(name, price);
this.warrantyMonths = warranty;
}
@Override
void description() {
System.out.printf("%s 保修期:%d个月\n", name, warrantyMonths);
}
}
// 支付接口
interface Payable {
boolean pay(double amount);
}
// 物流接口
interface Shippable {
void ship(String address);
}
// 具体商品实现
class Laptop extends Electronics implements Shippable {
public Laptop() {
super("高端笔记本", 9999.99, 24);
}
public boolean pay(double amount) {
System.out.println("信用卡支付:" + amount);
return true;
}
public void ship(String address) {
System.out.println("快递发货至:" + address);
}
}
第六章:常见陷阱与最佳实践
6.1 易犯错误
滥用继承:将"has-a"关系设计成继承
// 错误:汽车不是引擎的一种
class Car extends Engine { ... }
// 正确:使用组合
class Car {
Engine engine;
}
2.过度抽象:过早创建不必要的抽象
// 不需要抽象的情况
abstract class StringUtils { // 应改为final类+私有构造
static String reverse(String s) { ... }
}
6.2 设计原则
面向接口编程:声明变量时优先使用接口类型
List<String> list = new ArrayList<>(); // 正确 ArrayList<String> list = new ArrayList<>(); // 不够灵活
接口隔离原则:避免臃肿接口
// 错误:多功能混合接口 interface AnimalActions { void eat(); void fly(); void swim(); } // 正确:拆分接口 interface Flyable { void fly(); } interface Swimmable { void swim(); }
第七章:Java 17新特性——密封类与接口
7.1 密封类(Sealed Classes)
作用:限制类的继承
public abstract sealed class Shape permits Circle, Rectangle, Triangle { // 仅允许指定子类 } final class Circle extends Shape { ... }
7.2 密封接口
sealed interface FileFormat
permits JSON, XML, CSV { ... }
第八章:综合练习与答案
8.1 练习题
设计
Logger
抽象类,包含:- 抽象方法
log(String message)
- 具体方法
getTimestamp()
- 子类
FileLogger
和ConsoleLogger
- 抽象方法
创建
Authenticator
接口,包含:- 默认方法
encrypt(String password)
- 抽象方法
login(String user, String pass)
- 实现类
DatabaseAuthenticator
- 默认方法
8.2 参考答案
// 抽象Logger
abstract class Logger {
String getTimestamp() {
return Instant.now().toString();
}
abstract void log(String message);
}
class FileLogger extends Logger {
@Override
void log(String message) {
String entry = getTimestamp() + " - " + message;
// 写入文件...
}
}
// 认证接口
interface Authenticator {
default String encrypt(String password) {
return Base64.getEncoder().encodeToString(password.getBytes());
}
boolean login(String user, String password);
}
class DatabaseAuthenticator implements Authenticator {
@Override
public boolean login(String user, String pass) {
String encrypted = encrypt(pass);
// 数据库验证...
return true;
}
}
总结:
- 抽象类的定义与使用场景
- 接口的演进与现代特性
- 抽象类与接口的对比选择
- 面向接口编程的最佳实践
- 复杂系统的分层设计技巧