现实问题中,很多情况是需要多个不同类型的对象协作完成的。像在最简单的问题域 “张三有只叫小黑的狗” 中应该有几个类?
两个,对吧?人类和狗类。人类实例张三拥有姓名属性,狗类小黑实例也拥有姓名属性。再假设一个问题域 “李四用双立人刀切菜” 人类实例李四使用刀类名叫双立人的刀在切菜。再比如 “砂锅更适合炖汤” 当前就出现了锅类,锅的分支下还可以有砂锅、铁锅、平底锅等。但不管是什么类型材质的锅,都是属于锅类的。
对象的 3 种关联关系
从上述的几个场景中,我们可以分析出对象和对象间拥有:
- has-a 关系
- use-a 关系
- is-a 关系
顾名思义:
- has-a 就是 有一个,指在一个对象内部 “拥有” 另一个对象
- use-a 就是 用一个,指在一个对象的某个方法中“使用”另一个对象
- is-a 就是指 是一个,指的是一个对象是另外一种对象的特例
其中 is-a 被归属在继承关系,目前只包含前两种 has-a 和 use-a 关系。
has-a 关系
这是一种很常见的关联关系,就像我们提到过的问题域 “张三有只叫小黑的狗”,张三是一个对象,狗也是一个对象。所以在语法上,has-a 关系就是把一个对象设计为另一个对象的属性。在一个对象内部“拥有”另一个对象。
// Human.java
public class Human {
public String name; // 人名
public Dog pet; // Dog 类型的 pet
public Human(String name, Dog pet) {
this.name = name; // 赋值实例的名字
this.pet = pet; // 赋值实例的宠物
}
public void talk() {
System.out.println("我是" + this.name + "我的小狗是" + this.pet.name);
}
}
// Dog.java
public class Dog {
public String name;
public Dog(String name) {
this.name = name;
}
public void eat() {
System.out.println("汪汪!");
}
}
// TestMain.java
public class TestMain {
public static void main(String[] args) {
Dog xiaohei = new Dog("小黑"); // 创建狗类实例 xiaohei
Human zhangsan = new Human("zhangsan", xiaohei); // 创建人类实例 zhangsan
zhangsan.talk();
xiaohei.eat();
}
}
关联关系,还可以细分为单向关联和双向关联
- A has B 或 B has A 都属于单向关联
- A has B 且 B has A 叫作双向关联
把对方设计为自己的属性后,有一个特点在于:在当前对象的所有方法中,都可以访问到关联对象。换句话说,两个对象的生命周期是保持一致的,这就是所谓的你中有我,我是你的一部分。
use-a 关系
这种关系的关联度就要弱一些,从关联关系也能看出来是 “使用XX”。在语法上,是把一个对象设计为另一个对象的某个方法的局部变量。就好比是之前提到过的 “李四在用刀切菜” 不可能将刀设置为李四的属性吧?
该变量可以通过参数传递进这个方法,也可以在方法内部自己 new 出。无论采用哪种方式,都是 use-a 关系。无论是参数还是内部 new ,都是方法内部的局部变量,方法结束局部变量就消失,关系解除。
包
当程序越来越大,书写的类越来越多,文件们就需要一种结构能够进行存放和管理。于是就有了包的概念去分门别类地管理多个类。包在本质上就是用来专门管理 java 类的文件夹。
创建包的方式:对 src 文件夹右键 - 新建 - 软件包。包的命名规范:全小写。
当一个 java 类被放入到某个包中,有以下特点:
- 在该类的最高处要增加一句包声明的代码 package 包名; 例如 package traffic;
- 默认情况下,一个 java 类只能访问来自于同包的其他 java 类,如果需要访问其他包的类,需要导入 import 将那个类导入进来。就好比以前导入 Scanner 一样 import java.util.Scanner; 可以使用 import 包名.* 导入某个包下所有的类,但不建议这样做,尽量用哪些导哪些
- IDEA 工具中有多个创建包和创建类的方式
通常会在一个包中放所有 main() 方法的 java 类,再在其他包中放各种类。