相关概念:
依赖:
有A类和B类,若A类的变化影响了B类,则B依赖与A。
依赖关系三种情况:
1、A类是B类中的(某中方法的)局部
2、A类是B类方法当中的一个
3、A类向B类发送消息,从而影响B类发生
public class Pen {
public void draw() {
System.out.println("Drawing!");
}
}
public class Draw {
public void PenToDraw(Pen pen) { //pen作为Draw类方法的参数
pen.draw();
}
}
如果Pen类中执行的操作为Writing,则是用笔“写字”,Draw类会受到影响,Draw依赖于Pen
关联:
简单来说就是两类对象之间有联系,通常将一个类的对象作为另一个类的属性,或者引用了一个类型为被关联类的全局变量。
依赖中,Pen是作为方法的参数传入,而关联中,Pen作为Draw的属性:
public class Pen {
public void draw() {
System.out.println("Drawing!");
}
}
public class Draw {
private Pen pen; //pen(Pen类)作为You类的属性
public void PenToDraw() {
pen = new Pen();
pen.draw();
}
}
正题:
组合与聚合
组合和聚合都是关联的一种形式,描述了两个对象之间整体与部分的归属关系。
简单概念区分:
聚合关系:整体与部分可以分开,即一个对象可以被其他的聚集对象拥有,成员对象可以脱离整体独立存在。
组合关系:整体与部分不可分开,即一个对象只能归属与另一个对象,整体对象不存在则成员对象也不存在,成员依赖于整体。
深拷贝与浅拷贝:
聚合关系:在类中没有开辟新的空间 => 拷贝地址 => 浅拷贝
组合关系:在类中开辟了新的空间 => 拷贝内容 => 深拷贝
课堂案例
一本书Book只能写一个学科的Practice,而一支笔Pen可以写多个Practice。
Book与Practice是组合关系,Pen与Practice是聚合关系。
package test;
//Pen.java
public class Pen {
private int length;
private String color;
public Pen() {
length = 10;
color = "white";
}
public Pen(int length,String color) {
this.length = length;
this.color = color;
}
public void SetPen(int length,String color) {
this.length = length;
this.color = color;
}
public String toString() {
String str;
str = "length: " + length +
"\ncolor: " + color;
return str;
}
}
//Book.java
public class Book {
private int area;
private String color;
public Book() {
area = 20;
color = "white";
}
public Book(Book book) {
this.area = book.area;
this.color = book.color;
}
public Book(int area,String color) {
this.area = area;
this.color = color;
}
public void SetBook(int area,String color) {
this.area = area;
this.color = color;
}
public String toString() {
String str;
str = "area: " + area +
"\ncolor: " + color;
return str;
}
}
//Practice.java
public class Practice {
private String name;
private Pen pen;
private Book book;
public Practice(String name,Pen pen,Book book) {
this.name = name;
this.pen = pen; //聚合,把pen的地址拷贝给了this.pen
this.book = new Book(book); //组合,开辟一个新的内存空间
}
public void SetBook(Book newbook) {
book = new Book(newbook);
}
//聚合
public Pen getPen() {
return pen; //Pen本身不受Practice影响
}
//组合
public Book getBook() {
return new Book(book); //Book依赖于Practice
}
public String toString() {
String string;
string = "practice Name: " + name +
"\nPen Information:\n" + pen +
"\nBook Information:\n" + book;
return string;
}
}
//PracticeDemo.java
public class PracticeDemo {
public static void main(String[] args) {
Pen mypen = new Pen(100,"black");
Book mybook = new Book();
Practice mypractice = new Practice("math",mypen,mybook);
System.out.println(mypractice);//第一组输出
System.out.println();
mypen.SetPen(10,"red");
System.out.println(mypractice);//第二组输出
System.out.println();
mybook.SetBook(30,"brown");
System.out.println(mypractice);//第三组输出
System.out.println();
mypractice.SetBook(new Book(30,"brown"));
System.out.println(mypractice);//第四组输出
}
}
第一组输出:mypractice的初始值
practice Name: math
Pen Information:
length: 100
color: black
Book Information:
area: 20
color: white
第二组输出:通过SetPen()更新后
Pen类更新后,mypractice的Pen Information也随之变化,这是因为在Practice中pen引用的是现有类的地址,Pen类值改变,通过地址传入的值也改变。
拷贝地址->浅拷贝->聚合
practice Name: math
Pen Information:
length: 10
color: red
Book Information:
area: 20
color: white
第三组输出:通过SetBook()更新后
Book类更新后,mypractice的Book Information不改变,这是因为在Practice中book为新声明的变量,开辟新的存储空间,Book类值改变,但是mypractice仍为原先赋过来的内容。
拷贝内容->深拷贝->组合
practice Name: math
Pen Information:
length: 10
color: red
Book Information:
area: 20
color: white
第四组输出:通过mypractice中的SetBook()更新后
通过mypractice的SetBook()方法,向其中传入一个新的Book类,才能将这个类的内容赋值给mypractice中的book属性(更新),从而使最后的输出发生改变
practice Name: math
Pen Information:
length: 10
color: red
Book Information:
area: 30
color: brown