1. 类关系
1.1 继承关系
继承关系:是指一个类(子类)继承另一个类(父类)的属性和方法,实现代码的复用和扩展。在Java中,使用extends关键字表示继承关系,用空心三角形和实线表示这种继承关系。
例如: 狗类是动物类的子类,动物类为父类。狗类可以继承动物类的属性和方法,也可以扩展自己的属性和方法。
// 定义一个动物类
class Animal{
private String name;
public void shout() {
System.out.println("动物会发出叫声。");
}
}
// 定义一个狗类,继承动物类
class Dog extends Animal{
// 定义一个狗类特有的属性,品种
private String breed;
// 定义一个狗类特有的方法(行为)
public void wag() {
System.out.println("狗摇尾巴");
}
// 重写父类的方法
@Override
public void shout() {
System.out.println("狗会汪汪叫");
}
}
1.2 实现关系
实现关系:是指一个类(实现类)实现一个或多个接口(抽象类)的抽象方法,实现多态和规范。在Java中,使用implements关键字表示实现关系,用空心三角形和虚线表示这种实现关系。
例如: 定义一个交通工具接口,定义移动的抽象方法。汽车类实现交通工具接口,重写移动的方法。
// 定义一个交通工具接口
interface Vehicle{
// 定义一个抽象方法:移动
public void move();
}
// 定义一个交通工具的实现类汽车类
class Car implements Vehicle{
// 重写接口中的抽象方法
@Override
public void move() {
System.out.println("汽车在路上行驶");
}
}
1.3 依赖关系
依赖关系:是指一个类(依赖类)的实现依赖于另一个类(被依赖类),是一种比较临时的关系。依赖关系通常发生在一个类的方法中使用了另一个类的对象或者参数等。
在Java中,用虚线和箭头表示这种依赖关系,依赖类指向被依赖类。
例如: Customer类依赖于Vehicle类。通过构造方法注入依赖,Customer类可以使用Vehicle类的功能,而且可以轻松更改或替换Vehicle的实现,实现了松耦合的依赖关系。
//依赖关系的示例
public class Relation_04 {
//主程序
public static void main(String[] args) {
// 创建一个计算器实例
Calculator myCalculator = new Calculator();
// 创建一个数学操作实例,注入计算器依赖
MathOperations mathOps = new MathOperations(myCalculator);
// 使用数学操作进行加法
int result = mathOps.performAddition(5, 3);
// 输出结果
System.out.println("Result of addition: " + result);
}
}
//计算器类
class Calculator {
public int add(int a, int b) {
return a + b;
}
}
//数学操作类,依赖于计算器类
class MathOperations {
private Calculator calculator;
// 通过构造方法注入Calculator依赖
public MathOperations(Calculator calculator) {
this.calculator = calculator;
}
// 数学操作使用计算器
public int performAddition(int x, int y) {
return calculator.add(x, y);
}
}
1.4 关联关系
关联关系:是指两个类之间的联系,表示一个类与另一个类有某种关系,是一种比较长期的关系。关联关系通常表示为一个类的成员变量是另一个类的对象。在Java中,用实线和箭头表示这种关联关系,关联类指向被关联类。
例如: 一个作者(Author)类和一个书籍(Book)类,它们之间是一对多的关系,一个作者可以写多本书,一本书只能有一个作者。Author类是Book类的一方,Book类是Author类的多方。Author类和Book类通过对象的引用实现了关联关系。
//关联关系
//定义一个类:作者类
class Author {
//定义一个作者的属性:姓名
String name;
//定义一个作者的构造方法
public Author(String name) {
this.name = name;
}
//定义一个作者的方法:写书,参数为书籍类的对象
public void writeBook(Book book) {
//调用书籍类的方法,设置书籍的作者为当前对象
book.setAuthor(this);
System.out.println(name + "写了一本" + book.getTitle() + "书");
}
}
//定义一个类:书籍类
class Book {
public String getTitle() {
return title;
}
//定义一个书籍的属性:标题
private String title;
//定义一个书籍的属性:作者,表示书籍与作者的关联
private Author author;
//定义一个书籍的构造方法
public Book(String title) {
this.title = title;
}
//定义一个书籍的方法:设置作者,参数为作者类的对象
public void setAuthor(Author author) {
//将作者对象赋值给作者属性
this.author = author;
}
//定义一个书籍的方法:打印书籍信息
public void printInfo() {
System.out.println("书名:" + title + ",作者:" + author.name);
}
}
1.5 聚合关系
聚合关系:是关联关系的一种特例,表示整体和部分的关系,即has-a的关系。整体和部分之间是可分离的,拥有各自的生命周期。在Java中,用空心菱形和实线箭头表示这种聚合关系,菱形连接整体,箭头连接部分。一个类中的集合元素是另一个类的使用。
例如: 一个学校(School)类包含多个教师(Teacher)类的对象,表示学校有教师。教师类的对象可以脱离学校类的对象而存在,比如教师可以换学校。
public class Relation_02 {
User user;
public static void main(String[] args) {
// 聚合关系,user对象为独立的个体,虽然Relation_02中传入了user对象,但user对象不会因为Relation_02对象的销毁而销毁
User user = new User();
new Relation_02(user);
new Relation_02(user);
new Relation_02(user);
}
public Relation_02(User user) {
this.user = user;
System.out.println(user);
}
public Relation_02() {
User user = new User();
this.user = user;
System.out.println(user);
}
}
// 定义一个User类
class User{
}
// 聚合关系
//定义一个部分类:教师类
class Teacher {
//定义一个教师的属性:姓名
private String name;
//定义一个教师的构造方法
public Teacher(String name) {
this.name = name;
}
//定义一个教师的方法:教学
public void teach() {
System.out.println(name + "正在教学");
}
}
//定义一个整体类:学校类
class School {
//定义一个学校的属性:名称
private String name;
//定义一个学校的属性:教师数组,表示学校包含教师
private Teacher[] teachers;
//定义一个学校的构造方法
public School(String name, Teacher[] teachers) {
this.name = name;
this.teachers = teachers;
}
//定义一个学校的方法:运行
public void run() {
System.out.println(name + "正在运行");
//遍历教师数组,调用每个教师的教学方法
for (Teacher teacher : teachers) {
teacher.teach();
}
}
}
1.6 组合关系
组合关系:也是关联关系的一种特例,表示整体和部分的关系,即contains-a的关系。
这种关系比聚合更强,也称为强聚合。整体和部分是不可分割的,他们具有相同的生命周期。
在Java中,用实心菱形和实线箭头表示这种组合关系,菱形连接整体,箭头连接部分。
例如:一个电脑(Computer)类包含一个主板(Motherboard)类的对象,表示电脑有主板。主板类的对象不能脱离电脑类的对象而存在,因为主板是电脑的一部分。
// 组合关系
public class Relation_03 {
}
//定义一个部分类:主板类
class Motherboard {
//定义一个主板的属性:型号
private String model;
//定义一个主板的构造方法
public Motherboard(String model) {
this.model = model;
}
//定义一个主板的方法:启动
public void boot() {
System.out.println("主板" + model + "启动");
}
}
//定义一个整体类:电脑类
class Computer {
//定义一个电脑的属性:品牌
private String brand;
//定义一个电脑的属性:主板,表示电脑包含主板
private Motherboard motherboard;
//定义一个电脑的构造方法
public Computer(String brand, String model) {
this.brand = brand;
//在构造方法中创建主板类的对象
this.motherboard = new Motherboard(model);
}
//定义一个电脑的方法:运行
public void run() {
System.out.println("电脑" + brand + "运行");
//调用主板类的方法:启动
motherboard.boot();
}
}
2. 内部类
2.1 概述
内部类: 类体中的类叫做内部类
当一个事物的内部还需要另一个完整的结构时,并且该结构又只对当前类提供服务
这种情况下,就不需要单独创建实体类,而是把这个实体类写在这个类的内部即可。
内部类可以访问外部类的私有化属性。形式:class A {class B}
内部类的类名 = 外部类$内部类类名,此时编译器生成的class文件,B的名字为A$B
2.2 成员内部类
成员内部类可以等同看作成员变量,类体中没有static修饰
成员内部类可以使用权限控制符修饰
成员内部类中不能有静态声明,因为成员内部类依赖于外部类的实例而存在,而静态声明不依赖于实例,他们之间存在矛盾。
成员内部类可以直接访问外部类中的所有属性。
public class OuterClass {
private static int a = 2;
private int b = 3;
private class InnterClass{
//不能有静态声明
//static int c = 5;
//public static void m1(){}
int b = 4;
public void m2() {
System.out.println(a);
System.out.println(b);
//区分外部类与内部类的同名成员属性
System.out.println(OuterClass.this.b);
}
}
public static void main(String[] args) {
//创建外部类实例
OuterClass out = new OuterClass();
//通过外部类实例创建内部类对象
InnterClass inner = out.new InnterClass();
//调用内部类方法
inner.m2();
}
}
2.3 静态内部类
静态内部类可以看作静态变量,需要使用static修饰
静态内部类中可以声明静态也可以声明成员变量
静态内部类中,无法直接访问成员属性,需要创建对象
// 静态内部类
public class OuterClass_01 {
private static int a = 1;
private int b = 2;
public static class InnerClass{
// 可以声明静态方法
public static void m1() {
System.out.println(a);
}
// 也可以声明成员方法
public void m2() {
System.out.println(a);
// 不能直接访问成员变量
// System.out.println(b);
// 可以通过创建外部类对象访问成员变量
System.out.println(new OuterClass_01().b);
}
}
public static void main(String[] args) {
// 因为是静态声明,可以直接创建内部类对象
InnerClass inner = new InnerClass();
inner.m2();
InnerClass.m1();
}
}
2.4 局部内部类
局部内部类可以看作局部变量
局部内部类不能有静态声明
局部内部类的名字为: 外部类名$1内部类名,外部类名$2内部类名,以此类推
如果内部类访问外部类中的局部变量,该变量需要加final修饰,不可以二次赋值。1.8开始final可省略。
// 局部内部类
public class OutClass_02 {
private static int a = 1;
private int b = 2;
// 静态方法中的内部类
public static void m1() {
int c = 4;
// 成员内部类
class InnerClass{
// 成员内部类中不能有静态声明
// public static void m3() {};
public void m4() {
// 可以直接访问外部类的静态属性
System.out.println(a);
// 外部方法为静态方法时,不能直接访问成员变量
// System.out.println(b);
// 访问局部变量后,等于使用final修饰了,不能修改
System.out.println(c);
// c = 3;
}
}
// 使用局部内部类,只能在这个方法中使用
InnerClass inner = new InnerClass();
}
public void m2() {
class InnerClass {
public void m4() {
System.out.println(a);
// 成员方法的局部内部类,可以直接访问外部成员属性
System.out.println(b);
}
}
InnerClass innerClass = new InnerClass();
innerClass.m4();
}
}
2.5 匿名内部类
匿名内部类的类名为:外部类类名$1 以此类推
一般在方法调用时,需要传入一个对象的时候(一般是接口实现对象),这个时候如果这个类也不会再复用,就可以不创建class类,直接传入一个内部匿名类即可。
语法: 方法名(new 父类/父类接口(){匿名内部类的类体});
匿名内部类相当于直接创建一个临时使用的子类对象,不创建对应的子类文件
匿名内部类是不能进行复用的
匿名内部类中不能有静态声明,但是可以声明常量
匿名内部类不能直接访问外部的成员属性,需要有对象才行。
// 匿名内部类
public class OutClass_03 {
public static void main(String[] args) {
// 匿名内部类
test(new IUserService(){
public void login() {
System.out.println("登录成功");
}
});
// 匿名内部类
// 1.8新特性,lambda表达式,又叫箭头函数,是匿名内部类的简写形式
test(() -> System.out.println("登录成功"));
}
public static void test(IUserService userService) {
userService.login();
}
}
interface IUserService{
public void login();
}
3. 设计模式
3.1 概述
软件设计模式: 又称设计模式,是一套被反复利用,多数人知晓的,经过分类编目的,代码设计经验的总结。
使用设计模式是为了可重用代码,让代码更容易被他人理解,保证代码可靠性,程序的重用性。
3.2 单例模式
单例模式: 让某个类只创建一个对象,提供一个获取对象的方法,调用多次,得到的始终是同一个对象。
1. 构造方法私有化,不能让外部类直接访问。
2. 提供一个公共的静态方法,用于获取对象。
3. 提供一个静态变量用于保存对象。
根据对象的创建时机分为两种:
1. 懒汉模式
// 懒汉模式(线程不安全)
// 如果多个访问者同时去获取实例,就会造成同时存在多个实例存在
class Singleton_01 {
// 私有化构造方法
private Singleton_01() {
};
// 提供静态变量用于保存对象
static Singleton_01 instance;
// 提供共有的静态方法用于获取对象
public static Singleton_01 getInstance() {
// 若已经创建了对象,直接返回
if(instance != null) {
return instance;
}
// 否则创建对象
instance = new Singleton_01();
return instance;
}
}
2. 饿汉模式
// 饿汉模式(线程安全)
// 在程序启动时直接运行加载,后续有外部类需要使用时直接获取即可
// 无论在程序中是否用到这样的类,都会在程序启动时进行创建
public class Singleton_00 {
// 私有化构造方法
private Singleton_00() {
};
// 提供静态变量用于保存对象
static Singleton_00 instance = new Singleton_00();
// 提供共有的静态方法用于获取对象
public static Singleton_00 getInstance() {
return instance;
}
}