封装的直接作用是通过限制访问、统一入口和隐藏实现来保护数据与逻辑;耦合度降低是其自然结果而非直接目标。

封装本身不直接“降低类与类之间的耦合度”,它真正起作用的是:**通过限制访问 + 统一入口 + 隐藏实现**,让其他类只能依赖你暴露的接口,而不是你的字段、内部逻辑或数据结构。耦合度下降是这个过程的自然结果,不是封装的直接目标。
为什么 public 字段会立刻拉高耦合度
一旦把 age、username 这类字段声明为 public,外部代码就会直接读写它们:
- 其他类开始硬编码字段名,比如
user.age = 25; - 后续你想把
age拆成birthYear和timezone计算,所有调用处全得改; - 字段类型变更(如
String username→Username username)会引发编译失败,且无法做兼容过渡; - 根本没法在赋值时加校验、日志、通知等横切逻辑。
get/set 方法如何悄悄切断依赖链
getAge() 和 setAge(int) 看似只是包装一层,但它们构成了契约边界:
- 调用方只依赖方法签名,不关心 age 是存在字段里、缓存里,还是每次从数据库查;
- 你可以在
setAge里加条件:if (age 150) throw new IllegalArgumentException();; - 后续想把 age 改为只读,只需删掉
setAge,调用方编译报错明确,而非运行时崩; - IDE 或框架(如 Jackson、Hibernate)能自动识别标准 getter/setter,无需额外配置就能完成序列化或映射。
封装不到位时,耦合会藏在哪些地方
这些现象往往被误认为“功能正常”,实则已埋下高耦合隐患:
- 测试类里直接反射修改
private字段来绕过校验——说明业务逻辑没真正封装进方法; - DTO 类和 Entity 类字段名、类型、顺序完全一致,靠手动 copy 或 MapStruct 映射——本质是把数据结构耦合当成了“约定”;
- Service 层直接 new 一个 DAO 对象并调用其
connection字段——暴露了技术细节,换数据库驱动就得改 Service; - 前端 API 返回体字段名和后端 Java 字段名一模一样,连下划线/驼峰都不转换——前后端隐式绑定,改个字段名就得前后联调。
真正难的不是加 private 和生成 getter/setter,而是判断哪些逻辑该放进方法里、哪些状态该彻底不暴露、哪些接口该抽象成 interface 而非具体类——这些决策点,才是封装在架构层面产生价值的地方。










