封装的核心是通过private字段建立物理防线,阻止外部直接访问或修改对象内部状态;公共方法作为可控入口,可嵌入校验逻辑确保数据安全。

封装最直接的作用,就是让对象的内部状态不被外部“伸手就改”。它不是靠信任,而是靠机制——把字段设为 private,等于给数据加了一道门,门外代码没有钥匙,连门把手都摸不到。
私有字段是第一道物理防线
只要字段声明为 private,Java 编译器和运行时就会强制拦截任何跨类的直接读写。比如:
-
public class BankAccount { private double balance; }—— 外部类哪怕写account.balance = 999999;,编译直接报错 - 没有 getter/setter 的话,连“看一眼”或“动一下”的机会都没有
- 这和权限系统类似:不是劝你别删文件,而是根本没给你
rm权限
公共方法才是可控的“安检通道”
真正允许访问的入口(如 setBalance()),必须由类自己定义,并在里面嵌入校验逻辑:
- 传入负数?
if (amount - 试图绕过业务规则清空余额?方法里可以拒绝执行,或触发审计日志
- 甚至能记录谁在什么时候调用了什么操作,为追溯提供依据
防的不只是“恶意”,更是“误操作”和“越权依赖”
所谓“恶意篡改”,不一定来自攻击者。更多时候是:
- 同事写的工具类直接反射修改私有字段(但反射本身需要显式开启权限,且可被安全管理器拦截)
- 下游模块把某个字段当公开契约使用,一旦你后续加校验或改逻辑,它就崩了 —— 封装后,它只能走你开放的接口,你随时可升级内部实现而不破环兼容
- 多线程环境下,没有封装的共享字段可能被并发乱写;而封装后可通过同步、不可变返回值等方式守住一致性
配合不可变设计,彻底切断篡改路径
对关键状态,进一步用 final + 私有 + 只读接口 组合封死所有出口:
- 字段声明为
private final List<string> tags;</string> - getter 不返回原引用:
return Collections.unmodifiableList(tags); - 外部拿到的只是一个“只读快照”,add/remove 都会抛
UnsupportedOperationException - 连“善意帮忙修改”的余地都不留,从根源上杜绝状态漂移
封装不是把代码藏起来,而是把控制权收回来。它让对象成为自己状态的唯一合法管理者,而不是任人摆布的数据容器。










