Java类之间的关联关系

Java类之间的关联关系

分类: Java学习 3599人阅读 评论(3) 收藏 举报

Java类之间的关联关系

UML类图中的关系分为四种:泛化、依赖、关联、实现;关联关系又可以细化为聚合和组合。

一、泛化(Generalization)

泛化是父类和子类之间的关系,子类继承父类的所有结构和行为。在子类中可以增加新的结构和行为,也可以覆写父类的行为。

一般用一个带空心箭头的实线表示泛化关系,UML图如下:

泛化对应Java中继承关系,即子类继承父类中出private修饰外的所有东西(变量、方法等)。示例代码:

public class Animal {

}

public class Tiger extends Animal {

}

Tiger继承Animal,因此Tiger与Animal之间是泛化(继承)关系。这个很好理解。

二、依赖(Dependency)

依赖关系是一种使用关系,特定事物的改变有可能会影响到使用该事物的事物,反之不成立。在你想显示一个事物使用另一个事物时使用。

一般用一条指向被依赖事物的虚线表示,UML图如下:

通常情况下,依赖关系体现在某个类的方法使用另一个类作为参数。代码示例:

public class Screwdriver {    //螺丝刀,作为人类的工具,是用来被人类使用的

}

public class Person{

       public void screw(Screwdriver src){    //拧螺丝,需使用螺丝刀

}

}

Person类的screw()方法在使用时就得传入一个Screwdriver类型的参数,这样Screwdriver的改变就会影响到Person,因此Person与Screwdriver之间就是依赖关系(Person依赖于Screwdriver)。

三、关联(Association)

是一种结构关系,说明一个事物的对象与另一个事物的对象相联系。给定有关联的两个类,可以从一个类的对象得到另一个类的对象。关联有两元关系和多元关系。两元关系是指一种一对一的关系,多元关系是一对多或多对一的关系。两个类之间的简单关联表示了两个同等地位类之间的结构关系。当你想要表示结构化关系时使用关联。(可以想想Hibernate的关联关系)

一般用实线连接有关联的同一个类或不同的两个类。UML图如下:

通常情况下,关联关系是通过类的成员变量来实现的。代码示例:

public class Company {   //公司

private Employee emp ;  //一个公司雇员,公司与雇员之间就是一种关联关系。

}

public class Employee{

}

雇员作为公司的属性,不同于上面的依赖。依赖的话,雇员的改变会影响公司,显然不是。在这里雇员仅仅作为公司的一个属性而存在。因此Employee与Company之间是关联关系。关联关系还可以细分为聚合和组合两种。

3.1  聚合(Aggregation)

聚合是一种特殊的关联。它描述了“has a”关系,表示整体对象拥有部分对象。

关联关系和聚合关系来语法上是没办法区分的,从语义 上才能更好的区分两者的区别。聚合是较强的关联关系,强调的是整体与部分 之间的关系。例如,学校和学生的关系。聚合的整体和部分之间在生命周期上没有什么必然的联系,部分对象可以在整体对象创建之前创建,也可以在整体对象销毁之后销毁。

一般用带一个空心菱形(整体的一端-学校)的实线表示。UML图如下:

与关联关系一样,聚合关系也是通过类的成员变量来实现的。示例代码:

public class Student{

}

public class School{  

       private List<Student> students ;  //学校与学生是聚合关系

}

学校是整体,而学生是部分。学校与学生都是可以独立存在的,之间没有什么必然的联系。因此学校与学生就是聚合关系。

3.2  组合(Composition)

组合是聚合的一种形式,它具有更强的拥有关系,强调整体与部分的生命周期是一致的,整体负责部分的生命周期的管理。生命周期一致指的是部分必须在组合创建的同时或者之后创建,在组合销毁之前或者同时销毁,部分的生命周期不会超出组合的生命周期。例如Windows的窗口和窗口上的菜单就是组合关系。如果整体被销毁,部分也必须跟着一起被销毁,如果所有者被复制,部分也必须一起被复制。

一般用带实心菱形(整体的一端)的实线来表示。UML图如下:

与关联关系一样,组合关系也是通过类的成员变量 来实现的。示例代码:

public class Menu{

}

public class Window{

       private List<Menu> menus ;

}

菜单的存在前提是窗口的存在,两者之间存在很强的拥有关系。且窗口对菜单的生命周期负责,只有在窗口创建之后,菜单才能够创建,菜单必须在窗口销毁之前销毁。因此Window与Menu之间是组合关系。

聚合和组合的区别在于:

聚合关系是“has-a”关系,组合关系是“contains-a”关系;聚合关系表示整体与部分的关系比较弱,而组合比较强;聚合关系中代表部分事物的对象与代表聚合事物的对象的生存期无关,一旦删除了聚合对象不一定就删除了代表部分事物的对象。组合中一旦删除了组合对象,同时也就删除了代表部分事物的对象。

另外有一个差别是组合中的一个对象在同一时刻只能属于一个组合对象,而聚合的一个部分对象可以被多个整体对象聚合,例如一个学生可以在多个学校就读,而一个菜单在同一时刻只能是某个窗口内的对象。

四、实现(Realization)

实现关系指定两个实体之间的一个合约。换言之,一个实体定义一个合约,而另一个实体保证履行该合约。对类来说,就是一个类实现了一个接口。

一般用一条指向接口的虚线表示,UML图如下:

实现对应Java中的实现接口(implements)。示例代码:

public interface Person{

}

public class Student implements Person{

}

这个和泛化一样很好理解。

五、总结

类间关系有很多种,在大的类别上可以分为两种:纵向关系、横向关系。纵向关系就是继承关系,它的概念非常明确,也成为OO的三个重要特征之一,这里不过多的讨论。

横向关系较为微妙,按照UML的建议大体上可以分为四种:

依赖    (Dependency)

关联    (Association)

聚合    (Aggregation)

组合    (Composition)

关于关联,聚合,组合在实现上并没有显著区别,相区别他们只有通过判断关系双方之间的实际关系,如关系强弱、创建与销毁之间有无必要关联等。

它们的强弱关系是没有异议的:依赖 < 关联 < 聚合 < 组合<泛化(继承)

实现方式区别:

(1)    依赖关系:关系对象出现在局部变量或者方法的参数里,或者关系类的静态方法被调用

(2)    关联关系:关系对象出现在实例变量中

(3)    聚合关系:关系对象出现在实例变量中

(4)    合成关系:关系对象出现在实例变量中

(5)    Generalization: extends

(6)    实现: implements

<think>我们正在讨论Java之间关联关系关联关系之间的一种结构关系,它表示一个的对象与另一个的对象之间有联系。根据引用[1],关联关系是语义级别的一种强依赖关系,比依赖更强,具有长期性和平等性。关联可以是单向或双向的。 在代码层面,关联关系表现为一个(关联)中包含另一个(被关联)的属性。例如,A中有一个属性是B型,那么我们就说A关联了B。 在UML图中,关联关系用一条带箭头的实线表示,箭头从关联指向被关联(如果是单向关联)。在双向关联中,可以用两条箭头或一条不带箭头的线(但通常用带箭头的实线双向表示)。 引用[1]还提到,关联的两端可以标注角色名和多重性(例如1对1,1对多等)。 下面我们通过代码示例来详细说明: ### 1. 单向关联 单向关联是指只有一个持有对另一个的引用。 例如,我们有两个:`Person`(人)和`Address`(地址)。一个人有一个地址,但地址并不持有对拥有它的人的引用(单向关联)。 ```java class Address { private String street; private String city; public Address(String street, String city) { this.street = street; this.city = city; } // 省略getter和setter } class Person { private String name; private Address address; // Person关联Address public Person(String name, Address address) { this.name = name; this.address = address; } // 省略getter和setter } ``` 在这个例子中,`Person`有一个`Address`型的属性,因此`Person`关联`Address`。这是单向关联,因为`Address`并不知道哪些`Person`对象引用了它。 ### 2. 双向关联 双向关联是指两个互相持有对方的引用。 例如,我们有两个:`Company`(公司)和`Employee`(员工)。一个公司有多个员工,同时一个员工属于一个公司。 ```java class Employee { private String name; private Company company; // 员工关联公司 public Employee(String name) { this.name = name; } public void setCompany(Company company) { this.company = company; } // 省略其他方法 } class Company { private String name; private List<Employee> employees = new ArrayList<>(); // 公司关联多个员工 public Company(String name) { this.name = name; } public void addEmployee(Employee employee) { employees.add(employee); employee.setCompany(this); // 设置员工的所属公司为当前公司 } // 省略其他方法 } ``` 在这个例子中,`Employee`有一个`Company`型的属性,同时`Company`有一个`Employee`型的集合(表示多个员工)。这样,两个相互引用,形成双向关联。 ### 3. 关联的多重性 关联的多重性表示一个的对象与另一个的对象连接的数量。常见的有: - 一对一(1:1):例如,一个人有一个身份证号。 - 一对多(1:N):例如,一个公司有多个员工。 - 多对多(N:M):例如,一个学生可以选择多门课程,一门课程也可以被多个学生选择。 在代码中,多重性可以通过属性的型来体现。例如,一对一关联使用单个对象引用(如上面的`Person`和`Address`),一对多关联使用集合(如`Company`中的`List<Employee>`)。 ### 4. 关联与聚合、组合的区别 关联关系是一个宽泛的概念,聚合和组合是特殊的关联。 - 聚合:表示整体与部分的关系,部分可以脱离整体而存在。例如,汽车和轮胎,轮胎可以脱离汽车而存在(更换轮胎)。在代码中,聚合关系也是通过成员变量来实现,但通常通过构造方法或setter方法注入部分对象,且部分对象可以独立于整体对象存在。 - 组合:是一种强聚合,部分不能脱离整体而存在。例如,人和心脏,心脏不能脱离人而存在。在代码中,组合关系表现为整体对象负责创建部分对象,并在整体对象销毁时部分对象也销毁。 ### 总结 关联关系之间的一种长期、稳定的关系,它描述了不同的对象之间的结构关系。在代码中,关联关系表现为一个的成员变量是另一个型。关联可以是单向或双向,并且可以有一对一、一对多、多对多等不同形式。 §§相关问题§§ 1. 关联关系和依赖关系有什么区别? 2. 如何用UML图表示关联关系? 3. 聚合和组合在代码实现上有什么区别? 4. 双向关联可能会导致什么问题?如何避免?</think>### Java 之间关联关系详解 在面向对象编程中,**关联关系(Association)** 描述不同对象之间的长期、结构化连接。它比依赖关系更强,体现语义级别的强依赖(如"我和我的朋友"),具有长期性和平等性特征[^1]。以下是核心要点和代码示例: --- #### 一、关联关系的核心特征 1. **长期性** 关系持续存在,非临时性(如订单与客户)。 2. **平等性** 双方对象独立存在,无整体-部分约束(区别于聚合/组合)。 3. **方向性** 分单向关联和双向关联。 4. **多重性** 通过数字标记(如 `1..*`)表示连接数量(一对一、一对多等)。 --- #### 二、关联关系的代码实现 ##### 1. 单向关联(One-way Association) 一个持有另一个的引用,但反向不成立。 **示例:** 学生选课(学生知道课程,课程不感知学生) ```java class Course { private String name; public Course(String name) { this.name = name; } } class Student { private String id; private Course course; // 单向关联:Student持有Course的引用 public void selectCourse(Course course) { this.course = course; } } ``` ##### 2. 双向关联(Bi-directional Association) 双方互相持有引用,需维护一致性。 **示例:** 作者与书籍(作者知晓著作,书籍记录作者) ```java class Author { private String name; private List<Book> books = new ArrayList<>(); // 一对多关联 public void addBook(Book book) { books.add(book); book.setAuthor(this); // 维护双向关联 } } class Book { private String title; private Author author; // 反向引用 public void setAuthor(Author author) { this.author = author; } } ``` ##### 3. 多重性表示 | 关系型 | 代码表现 | UML 标记 | |------------|-----------------------------------|----------| | 一对一 (1:1) | `private Department department;` | `1` | | 一对多 (1:N) | `private List<Employee> staff;` | `1..*` | | 多对多 (N:M) | `private Set<Course> courses;` | `*` | --- #### 三、关联 vs 依赖 vs 聚合/组合 | 关系型 | 强度 | 生命周期 | 代码表现 | 示例 | |----------|--------|----------|------------------------|-------------------| | 依赖 | 弱 | 临时 | 方法参数/局部变量 | `obj.method(foo)` | | **关联** | **强** | **长期** | **成员变量** | 学生持有课程引用 | | 聚合 | 较强 | 独立 | 成员变量(整体-部分) | 汽车与轮胎 | | 组合 | 最强 | 一致 | 成员变量(整体创建部分)| 公司与其部门 | > **关键区别**:关联通过成员变量实现,而依赖通过方法参数/局部变量实现[^1]。 --- #### 四、UML 表示法 在 UML 图中,关联关系用 **带箭头的实线** 表示: - 单向关联:单箭头(如 `Student → Course`) - 双向关联:无箭头或双箭头(如 `Author ↔ Book`) - 多重性标记:箭头旁标注 `1`、`*`、`1..*` 等[^1]。 --- #### 五、使用场景 1. 需要长期保持对象间关系(如用户与订单) 2. 双方需互相访问数据(如社交网络中的好友关系) 3. 需明确约束对象数量(如银行账户与客户的一对多关系) > **注意**:双向关联需警惕循环引用问题,可通过弱引用或解耦设计避免内存泄漏。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值