Appearance
Java 基础 - 面向对象
本文主要介绍Java OOP 面向对象基础和相关类图
三大特性
封装
利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体。数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系。用户无需知道对象内部的细节,但可以通过对象对外提供的接口来访问该对象。
优点:
- 安全性增强: 封装可以隐藏实现细节,防止外部直接访问对象的内部数据,提高了安全性。
- 模块化: 封装支持将功能划分为模块,使得代码更易维护、调试和理解。
- 降低耦合度: 封装可以减少对其他类的依赖,降低了系统的耦合度,提高了代码的灵活性。
- 代码复用: 封装将相关的属性和方法组织在一起,便于复用,并支持继承和多态等特性。
举例:
java
public class BankAccount {
// 封装私有属性
private String accountNumber;
private double balance;
// 构造方法
public BankAccount(String accountNumber, double balance) {
this.accountNumber = accountNumber;
this.balance = balance;
}
// 封装方法
public void deposit(double amount) {
// 实现存款操作,可能涉及复杂的业务逻辑
this.balance += amount;
}
public void withdraw(double amount) {
// 实现取款操作,可能涉及复杂的业务逻辑
if (amount <= balance) {
this.balance -= amount;
} else {
System.out.println("余额不足");
}
}
// 提供对私有属性的访问方法(Getter)
public String getAccountNumber() {
return accountNumber;
}
public double getBalance() {
return balance;
}
}
在上述例子中,
BankAccount
类封装了账户的属性和相关操作。私有属性accountNumber
和balance
只能通过公共的方法进行访问,从而隐藏了内部细节。
继承
继承(Inheritance) 是面向对象编程中的一个核心概念,它允许一个类(子类)继承另一个类(父类)的属性和方法。子类可以拥有父类的特性,并且可以在此基础上添加新的特性或修改已有的特性。
继承实现了 IS-A 关系,例如 Cat 和 Animal 就是一种 IS-A 关系,因此 Cat 可以继承自 Animal,从而获得 Animal 非 private 的属性和方法。
继承应该遵循里氏替换原则,子类对象必须能够替换掉所有父类对象。
Cat 可以当做 Animal 来使用,也就是说可以使用 Animal 引用 Cat 对象。父类引用指向子类对象称为 向上转型 。
优点:
- 代码复用: 继承可以使子类重用父类的代码,减少代码冗余,提高了代码的可维护性。
- 扩展性: 可以通过在子类中添加新的属性和方法,扩展父类的功能,使代码更加灵活。
- 维护性: 在父类中修改代码会影响所有子类,从而减小了维护成本。
- 多态: 继承是实现多态的基础,子类对象可以被当做父类对象使用,提高了程序的灵活性。
举例:
java
// 父类
class Animal {
String name;
// 构造方法
public Animal(String name) {
this.name = name;
}
// 方法
void eat() {
System.out.println(name + " is eating.");
}
}
// 子类
class Dog extends Animal {
// 子类可以继承父类的属性和方法,并可以添加新的属性和方法
// 构造方法
public Dog(String name) {
// 使用 super 调用父类的构造方法
super(name);
}
// 新的方法
void bark() {
System.out.println(name + " is barking.");
}
}
// 使用继承的例子
public class Main {
public static void main(String[] args) {
// 创建 Dog 对象
Dog myDog = new Dog("Buddy");
// 调用继承自父类的方法
myDog.eat();
// 调用子类新增的方法
myDog.bark();
}
}
在上述例子中,
Dog
类继承了Animal
类的属性和方法,同时添加了新的方法bark
。通过继承,Dog
类可以重用Animal
类的代码,实现了代码复用和扩展。
类图
UML(Unified Modeling Language) 是一种用于软件系统设计和建模的标准化建模语言,其中类图是UML中最常用的一种图表之一。类图用于描述系统中的类、对象及它们之间的关系,提供了对系统结构的可视化表示。
泛化关系 (Generalization)
泛化关系(Generalization) 是UML类图中的一种关系,用于表示类之间的继承关系,在 Java 中使用 extends
关键字。在继承关系中,一个类(称为子类或派生类)可以继承另一个类(称为父类或基类)的属性和方法。泛化关系用一条带空心三角形的线表示,箭头指向父类。
- 箭头方向:箭头指向父类,表示子类继承自父类。子类是一种特殊化的父类,拥有父类的所有特征和行为,并且可以额外定义自己的特征和行为。
- 标签:通常在箭头的中间或旁边标注继承关系的名称,用来描述子类与父类之间的关系。
- 继承关系:
- 子类继承父类的所有公共(public)和受保护(protected)的属性和方法。
- 子类可以重写(override)继承的方法,以满足自身的需求。
- 抽象类:父类可以是抽象类,表示不能被实例化的类,而只能被子类继承。抽象类通常包含至少一个抽象方法,子类必须实现这些抽象方法。
Car类继承自Vehicle类
sh
@startuml
class Vehicle {
- fuel: String
+ start(): void
+ stop(): void
}
class Car {
- brand: String
+ drive(): void
}
Vehicle <|-- Car
@enduml
在这个示例中,
Car
类继承自Vehicle
类。Vehicle
类是一个通用的交通工具,而Car
类是Vehicle
的特殊化,它继承了Vehicle
的属性和方法,并且可以添加自己的特有属性和方法,比如brand
和drive
。箭头指向Vehicle
,表示Car
是Vehicle
的子类。
实现关系 (Realization)
实现关系(Realization) 是UML类图中的一种关系,用于表示类与接口之间的关联,在 Java 中使用 implements
关键字。在实现关系中,一个类可以实现一个或多个接口,从而表明它遵循了这些接口定义的规范,并实现了接口中声明的方法。
- 箭头方向:箭头指向接口,表示类实现了该接口。接口是一种抽象规范,而类通过实现接口来提供具体的实现。
- 虚线:实现关系通常用虚线表示,以区别于实线的关联关系。
- 标签:通常在箭头的中间或旁边标注实现关系的名称,以描述类与接口之间的关系。
- 接口:接口是一种纯抽象的类,它只包含方法的签名而没有具体实现。通过实现接口,类承诺提供这些方法的具体实现。
实现关系-Circle实现Shape
sh
@startuml
class Shape {
+ draw(): void
}
class Circle {
+ radius: double
+ draw(): void
}
Shape <|.. Circle
@enduml
在这个示例中,
Circle
类实现了Shape
接口。接口Shape
定义了一个draw
方法,而Circle
类通过实现Shape
接口,提供了draw
方法的具体实现。箭头指向Shape
,表示Circle
类实现了Shape
接口。通过这种方式,可以确保Circle
类包含了Shape
接口中定义的方法。
聚合关系 (Aggregation)
聚合关系(Aggregation) 是 UML 类图中用于表示整体与部分之间的关系的一种关系。在聚合关系中,一个类可以包含另一个类的对象,但它们之间的关系不是强依赖关系。聚合关系通常用一条带空心菱形的线表示。
聚合关系-Department包含Employee
sh
@startuml
class Department {
- name: String
}
class Employee {
- id: int
- name: String
}
Department *-- "0..*" Employee : contains
@enduml
在这个例子中,
Department
类和Employee
类之间建立了聚合关系。关系使用*--
表示,而0..*
表示一个Department
可以包含零个或多个Employee
。带有空心菱形的线表示聚合关系,其中箭头指向整体(Department
),而菱形指向部分(Employee
)。这表示Department
包含了Employee
,但它们之间的关系是松散的,Employee
对象可以属于零个或多个Department
。
关联关系 (Association)
关联关系(Association) 表示不同类对象之间有关联,这是一种静态关系,与运行过程的状态无关,在最开始就可以确定。因此也可以用 1 对 1、多对 1、多对多这种关联关系来表示。比如学生和学校就是一种关联关系,一个学校可以有很多学生,但是一个学生只属于一个学校,因此这是一种多对一的关系,在运行开始之前就可以确定。
- 实线连接:类之间的关联关系通常用实线表示,连接两个类的名称之间。
- 角色:在关联线的两端,可以标注角色,表示每个类在关联中的作用或角色。
- 多重性:表示一个类的实例与另一个类的实例之间的数量关系。常见的多重性包括
1
(一个)、*
(多个)、0..1
(零个或一个)、0..*
(零个或多个)等。
关联关系-Person关联Address
sh
@startuml
class Person {
- id: int
- name: String
}
class Address {
- street: String
- city: String
}
Person -- Address : has
@enduml
在这个示例中,
Person
和Address
之间建立了关联关系。关联关系使用实线表示,并使用关联名称has
。这表示每个Person
对象都有一个相关联的Address
对象,而每个Address
对象也可以与多个Person
对象相关联。
依赖关系 (Dependency)
依赖关系(Dependency) 是UML类图中一种表示类之间关系的关系。它表示一个类的变化可能会影响到另一个类的情况。依赖关系通常用虚线箭头表示,箭头的方向指向被依赖的类。
- 虚线箭头连接:依赖关系使用虚线箭头连接依赖的类,箭头的方向指向被依赖的类。
- 依赖方向:如果类 A 依赖于类 B,表示类 A 中的变化可能会影响到类 B。在箭头指向的类是被依赖的类。
- 例子:依赖关系通常体现为一个类使用另一个类的实例、参数、方法等。当一个类的方法使用到另一个类的对象时,就形成了依赖关系。
依赖关系-Driver依赖Car
sh
@startuml
class Car {
+ drive(): void
}
class Driver {
+ operateVehicle(vehicle: Car): void
}
Driver --> Car : depends
@enduml
在这个示例中,
Driver
类依赖于Car
类。Driver
类中的operateVehicle
方法接受一个Car
对象作为参数,表明Driver
类依赖于Car
类。依赖关系用depends
标签表示。这表示Driver
类的变化可能会受到Car
类的影响。