在 Java 中,类之间的关系是面向对象设计的核心概念之一,理解这些关系能帮助你构建灵活、可维护的系统。以下是 继承(Inheritance)、实现(Implementation)、组合(Composition)、聚合(Aggregation)、依赖(Dependency)、关联(Assocition) 等关系的详细解析,结合代码示例和实际应用场景说明。
一、继承(Inheritance)
定义
子类(派生类)继承父类(基类)的属性和方法,并可以扩展或重写它们。
● 代码语法:extends 关键字。
● 核心特点:is-a 关系(例如:Dog 是 Animal)。
代码示例
// 父类
class Animal {
void eat() {
System.out.println("Animal is eating");
}
}
// 子类继承父类
class Dog extends Animal {
void bark() {
System.out.println("Dog is barking");
}
}
// 使用
Dog dog = new Dog();
dog.eat(); // 继承父类方法
dog.bark(); // 子类特有方法
应用场景
● 复用已有类的代码(如 List 接口的实现类 ArrayList)。
● 多态性(父类引用指向子类对象)。
注意事项
● 避免过度继承(容易导致类层次复杂)。
● 优先使用组合替代继承(防止父类修改影响子类)。
问题:怎么表示类中的方法,以及成员变量?
二、实现(Implementation)
定义
类实现接口(Interface)中定义的方法,满足接口的契约。
● 代码语法:implements 关键字。
● 核心特点:can-do 关系(例如:Car 可以 Drivable)。
代码示例
// 接口
interface Drivable {
void drive();
}
// 类实现接口
class Car implements Drivable {
@Override
public void drive() {
System.out.println("Car is driving");
}
}
// 使用
Drivable car = new Car();
car.drive();
UML 表示
应用场景
● 定义行为契约(如 Runnable 接口)。
● 解耦代码(通过接口隔离实现)。
注意事项
● 接口可以多实现,类只能单继承。
● Java 8+ 后接口支持默认方法(default)。
三、组合(Composition)
定义
整体对象拥有部分对象,且部分对象不能独立于整体存在(强生命周期绑定)。
● 核心特点:has-a 关系(例如:House 拥有 Room)。
代码示例
class Engine {
void start() {
System.out.println("Engine started");
}
}
class Car {
private final Engine engine; // 组合关系:Car 拥有 Engine
public Car() {
this.engine = new Engine(); // Engine 的生命周期由 Car 管理
}
void startCar() {
engine.start();
}
}
// 使用
Car car = new Car();
car.startCar(); // Engine 随 Car 的创建而创建,随 Car 销毁而销毁
UML 表示
应用场景
● 强关联关系(如订单和订单项)。
● 需要控制部分对象的生命周期。
四、聚合(Aggregation)
定义
整体对象包含部分对象,但部分对象可以独立存在(弱生命周期绑定)。
● 核心特点:has-a 关系(例如:University 包含 Professor)。
代码示例
class Professor {
void teach() {
System.out.println("Professor is teaching");
}
}
class University {
private List<Professor> professors; // 聚合关系:University 包含 Professor
public University(List<Professor> professors) {
this.professors = professors; // Professor 可以独立存在
}
}
// 使用
Professor p1 = new Professor();
Professor p2 = new Professor();
University university = new University(List.of(p1, p2));
UML 表示
应用场景
● 弱关联关系(如购物车和商品)。
● 部分对象需要被多个整体共享。
五、依赖(Dependency)
定义
一个类临时使用另一个类的方法或属性,但没有长期持有关系。
● 核心特点:uses-a 关系(例如:ReportGenerator 依赖 Database)。
代码示例
class Database {
void query(String sql) {
System.out.println("Executing query: " + sql);
}
}
class ReportGenerator {
void generateReport(Database db) { // 依赖关系:通过方法参数传递
db.query("SELECT * FROM data");
}
}
// 使用
Database db = new Database();
ReportGenerator generator = new ReportGenerator();
generator.generateReport(db); // 临时依赖
UML 表示
应用场景
● 方法参数、局部变量或返回值中使用其他类。
● 松耦合设计(如策略模式中的策略接口)。
六、关联(Association)
定义
类之间长期持有对方引用,可以是单向或双向。
● 核心特点:knows-a 关系(例如:Student 关联 Course)。
代码示例
class Course {
private String name;
// 其他属性和方法...
}
class Student {
private Course course; // 关联关系:长期持有 Course 引用
public void enroll(Course course) {
this.course = course;
}
}
// 使用
Student student = new Student();
Course course = new Course();
student.enroll(course);
UML 表示
应用场景
● 对象间长期协作(如用户和订单)。
● 双向关联需谨慎(可能导致循环依赖)。
七、关键区别与选择原则
关系类型 生命周期依赖 代码表现 典型场景
组合 强 成员变量直接初始化 汽车与引擎
聚合 弱 通过构造函数或Setter注入 大学与教授
依赖 无 方法参数、局部变量 工具类方法的参数
关联 长期持有 成员变量引用 学生与课程
继承 强 extends
关键字 动物与狗
实现 无 implements
关键字 类实现接口(如 Runnable)
设计原则
- 优先组合而非继承(减少耦合,提高灵活性)。
- 依赖倒置原则:依赖抽象(接口),而非具体实现。
- 单一职责原则:避免一个类承担过多职责。
八、总结
● 继承:用于 is-a 关系,但需谨慎使用。
● 组合/聚合:用于 has-a 关系,组合更强调生命周期绑定。
● 实现:定义行为契约,支持多态。
● 依赖/关联:描述对象间的协作方式。
核心思想:根据实际需求选择合适的关系,优先使用组合和接口,保持代码灵活性和可维护性。
九、问题及个人理解
- 聚合、组合、依赖、关联这几个应该怎么理解
答:聚合和组合强调的是整体和部分的关系,都表示整体是由部分组成.这两种的区别是组合表示整体消失了,部分也将不存在.在代码中体现的是部分的生命周期是由整体来进行管理,或者说是构造整体的时候部分将一起构造.聚合表示整体消失了,部分仍可以继续存在;代码体现中体现是可以先构造部分,也将部分作为整体构造函数的入参.依赖、关联都表示一个类A使用另外一个类B;区别是关联是A长期持有B,作为成员变量,依赖是常用于方法参数、局部变量或返回值中使用其他类;关联和聚合、组合的相同点是都常用于成员变量;但是聚合、组合是强调整体和部分的关系;