Java封装过程中的getter/setter究竟有什么用?
一、没有 get/set
的世界(直接暴露字段)
假设你有一个表示 “银行账户” 的类,直接把余额 balance
暴露给外部:
public class BankAccount {// 余额直接暴露,任何人都能修改public double balance;
}// 外部代码
BankAccount account = new BankAccount();
// 问题1:可以直接修改余额(比如偷偷改大)
account.balance = 9999999;
// 问题2:可以把余额设为负数(逻辑上不合理)
account.balance = -1000;
问题:
- 外部代码可以随意修改内部数据(比如把余额改到无限大)。
- 无法阻止非法数据(比如负数余额)。
- 未来如果想加逻辑(比如修改余额时记录日志),必须改动所有使用这个类的代码。
二、有 get/set
的世界(封装字段)
现在用 private
隐藏字段,通过 get/set
控制访问:
public class BankAccount {// 余额私有化,外部无法直接访问private double balance; // 只读:只能获取余额,不能直接修改public double getBalance() {return balance;}// 可控修改:修改余额时必须走这里public void setBalance(double balance) {// 验证逻辑:余额不能为负数if (balance < 0) {System.out.println("余额不能为负!设置失败");return;}// 业务逻辑:修改余额时记录操作(比如日志)System.out.println("修改余额:" + this.balance + " → " + balance);this.balance = balance;}
}// 外部代码
BankAccount account = new BankAccount();
// 情况1:尝试设为负数(被拦截)
account.setBalance(-100); // 输出:余额不能为负!设置失败
// 情况2:正常修改
account.setBalance(1000); // 输出:修改余额:0.0 → 1000
// 情况3:尝试直接修改(编译报错,因为 balance 是 private)
// account.balance = 99999; // 报错:The field BankAccount.balance is not visible
安全点:
-
数据访问可控:
- 外部只能通过
getBalance()
看余额(只读),通过setBalance()
改余额(必须走验证)。 - 想偷改余额?没门,因为
balance
是private
的。
- 外部只能通过
-
非法数据拦截:
- 在
setter
里加逻辑(比如if (balance < 0)
),直接阻止不合理的数据。
- 在
-
扩展灵活:
- 未来想加功能(比如修改余额时发短信通知),只需要改
setBalance
方法,外部代码完全不用动。
- 未来想加功能(比如修改余额时发短信通知),只需要改
三、生活中的类比(理解封装)
把 BankAccount
类想象成一个真实的银行账户:
private balance
→ 你的 “实际余额”(银行内部才能直接碰)。getBalance()
→ “查询余额”(你能看,但不能改)。setBalance()
→ “柜台 / ATM 存钱”(必须走银行的流程,比如验证金额、记录操作)。
如果银行允许你直接改余额(像暴露 public balance
那样),世界就乱套了;但通过 get/set
(柜台流程),银行就能控制修改的合法性,这就是封装的意义。
四、总结:get/set
如何让代码更安全
- 隐藏内部实现:用
private
把字段藏起来,外部无法直接操作。 - 控制修改逻辑:在
setter
里加验证、日志、权限检查等逻辑。 - 隔离变化影响:未来修改内部逻辑(比如换存储方式),外部代码不用改。
简单说,get/set
不是安全的全部,但它是 “让类自己控制数据如何被访问和修改” 的基础,这就是面向对象中 封装 的核心价值。
如果现在还觉得抽象,记住一个原则:永远让字段是 private
的,用 get/set
当 “门卫” —— 门卫(get/set
)能检查每一个想进来(修改数据)的人是否合法。