一、前言
记录时间 [2024-05-11]
系列文章简摘:
面向对象 01:Java 面向对象相关内容整体概述
面向对象 02:区分面向过程与面向对象,类和对象的关系
面向对象 03:类与对象的创建、初始化和使用,通过 new 关键字调用构造方法,以及创建对象过程的内存分析
更多 Java 相关文章,请参考专栏哦。
本文讲述面向对象编程的三大特性之——封装。通过案例分析,简单介绍了封装的含义和作用,以及在 Java 中如何使用封装。
面向对象编程(Object-Oriented Programming, OOP)的三大特性是封装、继承和多态,这三大特性是 OOP
的基础,为设计灵活、可维护和可扩展的软件系统提供了核心机制。
这三个特性共同构成了面向对象编程的基础,使开发者能够设计出高内聚、低耦合的软件系统,促进了软件工程的高效管理和复杂问题的有效解决。
- 高内聚:一个模块内部各个组成部分(如类的方法、函数、变量等)之间应该紧密关联,共同完成一个具体且单一的功能,不允许外部干涉。
- 低耦合:各模块之间的依赖关系应该尽可能地减少和简化,一个模块应尽量少地依赖其他模块,模块之间的接口应清晰、简单,且只暴露必要的功能给外部使用。
二、封装概述
封装的基本思想:将对象的状态(数据成员,即属性)和行为(成员方法,即操作数据的方法)捆绑在一起,并对外界隐藏其内部实现细节的过程。
实现方式:在 Java 等面向对象编程语言中,封装是通过访问修饰符(如 public
,private
,protected
等)、构造器、getter
和 setter
方法等机制来实现的。通过这些手段,开发者可以精确控制类的哪些部分对外界开放,哪些部分保持内部私有。
封装的作用:封装不仅保护了数据的完整性,还提高了代码的模块化程度,使得代码更容易理解、维护和重用。具体如下。
- 信息隐藏:将对象的内部细节(某些属性、方法)设置为私有
private
,只暴露有限的公共接口(如getter
和setter
方法)供外部使用,防止外部代码直接访问和修改这些内部状态。从而减少意外修改数据的风险,增加程序的健壮性。 - 模块化:封装促进了代码的模块化,使得每个对象成为一个独立的单元,可以单独开发、测试和维护。这不仅简化了代码的复杂性,也提高了代码的可复用性。
- 易于使用:封装简化了对象的接口,使得用户不需要了解对象内部复杂的实现细节就能使用它。用户只需要知道对象能做什么(通过其提供的方法),而不是怎么做,这符合黑盒设计原则。
- 增强安全性:限制对对象内部数据的直接访问,可以实施更精细的控制逻辑,如数据验证,确保数据的完整性和一致性。
- 提高可维护性和扩展性:由于内部实现细节对外部是隐藏的,当需要修改对象内部实现时,不会影响到使用该对象的其他代码,这使得软件更容易维护和升级。同时,良好的封装也为后续添加新功能提供了便利。
三、如何实现封装
在 Java 中,实现封装主要依靠以下几个关键技术手段:访问修饰符、getter
和 setter
方法、构造器等。
1. 访问修饰符
- private:这是封装的核心,用于限制成员变量和方法的访问权限,使其仅对类内部可见。这可以防止外部代码直接访问和修改内部状态。
- public:用于公开类、方法或变量,使其对所有类可见。
- protected:允许同一包内的类以及所有子类访问。
- 默认(没有显式修饰符):允许同一包内的类访问。
2. Getter 和 Setter 方法
- Getter 方法:获取器,用于返回私有成员变量的值,让外部可以读取但不能直接修改这些值。
- Setter 方法:设置器,用于设置私有成员变量的值,通常会加入数据验证逻辑,确保数据的合法性。
3. 构造器
构造器用于创建对象时初始化成员变量,可以是无参构造器或带参数的构造器,通过构造器可以控制对象创建时的必要条件和初始化状态。
(构造器部分在上一篇文章中有详细阐述)
四、封装案例分析
假设有一个 BankAccount
类,我们希望封装账户余额,仅通过特定方法暴露余额的读取和更新。
首先,在这个类中,成员变量 balance
是私有的,不能被其他类直接访问。
// 私有成员变量,余额
private double balance;
想要访问这个内部变量,需要通过一些方法。
1. 构造方法初始化
使用 new
关键字实例化对象时,会调用对应的构造方法。
BankAccount bankAccount = new BankAccount(500);
可以通过该方法存入金额。如果初始化余额 >=0
,说明金额是合法的,存入私有变量 balance
;反之,则不合法,返回错误。
// 构造器
public BankAccount(double initialBalance) {// 如果初始化余额大于等于 0 ,合法,将值赋给 balanceif (initialBalance >= 0) {balance = initialBalance;} else {// 如果初始化余额小于 0 ,不合法,抛出异常throw new IllegalArgumentException("Initial balance cannot be negative.");}}
2. Getter / Setter 方法
Getter 方法用于返回私有成员变量的值;Setter 方法用于设置私有成员变量的值。
// Getter 方法
public double getBalance() {return balance;
}// Setter 方法
public void setBalance(double balance) {// 与构造方法类似,可以在前面增加一些判断条件this.balance = balance;
}
使用 Getter
方法获取余额:
// Getter 方法获取余额
System.out.println(bankAccount.getBalance());
Setter
方法用于设置余额的值,与构造方法类似,具体使用如下:
// Setter 方法设置余额的值
bankAccount.setBalance(600);
3. 存入金额
Setter
方法用于修改变量的值,存入 / 取出金额就是相当于让金额增加,也算是一种修改。
因此,存入 / 取出金额也需要使用 Setter
方法。
存入金额方式:写入需要存入的金额,然后加到原来的余额上,模拟追加存款。
// Setter 方法,存入金额
public void deposit(double amount) {// 加入数据验证,存入金额需要大于 0if (amount > 0) {// 加到原来的余额上,模拟追加存款balance += amount;} else {// 金额不合法,抛出异常throw new IllegalArgumentException("Deposit amount must be positive.");}
}
具体使用方式:
// 模拟追加存款
bankAccount.deposit(200);
System.out.println("追加存款后:" + bankAccount.getBalance());
4. 取出金额
取出金额方式:写入需要取出的金额,然后从原先的金额上面扣除,模拟取出部分存款。
// Setter 方法,取出金额
public void withdraw(double amount) {// 判断:取出金额的数量不能超过存款,且大于 0if (amount > 0 && amount <= balance) {// 从原先的金额上面扣除balance -= amount;} else {// 金额不合法,抛出异常throw new IllegalArgumentException("Invalid withdrawal amount.");}
}
具体使用方式:
// 模拟取出部分存款
bankAccount.withdraw(100);
System.out.println("取出存款后:" + bankAccount.getBalance());
五、完整测试代码
1. BankAccount 类
public class BankAccount {private double balance; // 私有成员变量,余额// 构造器public BankAccount(double initialBalance) {if (initialBalance >= 0) {balance = initialBalance;} else {throw new IllegalArgumentException("Initial balance cannot be negative.");}}// Getter方法public double getBalance() {return balance;}// Setter方法
// public void setBalance(double balance) {
// this.balance = balance;
// }// Setter 方法,存入金额public void deposit(double amount) {// 加入数据验证,存入金额需要大于 0if (amount > 0) {// 加到原来的余额上,模拟追加存款balance += amount;} else {// 金额不合法,抛出异常throw new IllegalArgumentException("Deposit amount must be positive.");}}// Setter 方法,取出金额public void withdraw(double amount) {// 判断:取出金额的数量不能超过存款,且大于 0if (amount > 0 && amount <= balance) {// 从原先的金额上面扣除balance -= amount;} else {// 金额不合法,抛出异常throw new IllegalArgumentException("Invalid withdrawal amount.");}}
}
2. 测试类
public class Application {public static void main(String[] args) {// new 实例化对象// 初始化余额为 500BankAccount bankAccount = new BankAccount(500);// Getter 方法获取余额System.out.println("当前余额为:" + bankAccount.getBalance());// Setter 方法设置余额的值
// bankAccount.setBalance(600);// 模拟追加存款bankAccount.deposit(200);System.out.println("追加存款后:" + bankAccount.getBalance());// 模拟取出部分存款bankAccount.withdraw(100);System.out.println("取出存款后:" + bankAccount.getBalance());}
}
六、总结
本文讲述面向对象编程的三大特性之——封装。通过案例分析,简单介绍了封装的含义和作用,以及在 Java 中如何使用封装。
一些参考资料
狂神说 Java 零基础:https://www.bilibili.com/video/BV12J41137hu/
TIOBE 编程语言走势: https://www.tiobe.com/tiobe-index/
Typora 官网:https://www.typoraio.cn/
Oracle 官网:https://www.oracle.com/
Notepad++ 下载地址:https://notepad-plus.en.softonic.com/
IDEA 官网:https://www.jetbrains.com.cn/idea/
Java 开发手册:https://developer.aliyun.com/ebook/394
Java 8 帮助文档:https://docs.oracle.com/javase/8/docs/api/