封装的核心是private字段+public方法组合约束,而非简单包代码;private字段切断外部直连,强制通过getter/setter访问,实现计算返回、副本保护、参数校验等控制。

封装不是“把代码包起来”就完事,而是通过访问控制机制明确谁可以读、谁可以改、谁只能看——核心在于 private 字段 + public 方法的组合约束。
为什么 private 字段必须配 getter/setter 才算封装?
直接把字段设为 public,哪怕加了注释说“别乱改”,编译器不拦、IDE 不报错、运行时也不校验——这等于没封。真正的封装起点是字段私有化,再由方法接管访问入口:
-
private字段切断外部直连,强制走方法路径 -
getter可以返回计算值(如getAge()基于birthYear计算)、或返回不可变副本(如return new ArrayList(internalList)) -
setter可做校验(如if (value ),而字段赋值做不到这点 - 不暴露字段名和类型细节:比如内部用
int存状态码,getStatusDesc()却返回String,上层完全无感
protected 和包级访问(默认)在封装中实际怎么用?
它们不是封装的“退让”,而是有明确协作边界的封装延伸:
-
protected允许子类访问,但禁止无关类触碰——适合模板方法模式中留给子类重写的钩子方法,或需继承复用的受控状态字段 - 包级访问(无修饰符)适用于“同一模块内高内聚协作”,比如
HttpService类依赖的RequestBuilder和ResponseParser都在http包下,彼此可直接调用,但对外仍隐藏 - 误用风险:把本该
private的字段设成protected,会导致子类意外修改关键状态;设成包级却把类随意挪到其他包,会破坏封装契约
哪些看似封装、实则失效的写法要立刻改掉?
这些代码表面上有 private 和方法,但封装逻辑已崩坏:
立即学习“Java免费学习笔记(深入)”;
- 字段
private,但setter直接赋值且不做任何检查(如public void setCount(int count) { this.count = count; })——等同于开放字段 - 返回可变对象引用:
public List,调用方能直接getItems() { return items; } add()或clear(),破坏内部一致性 - 用
public static final暴露集合常量:public static final List,虽不可重新赋值,但内容仍可被修改(SUPPORTED_TYPES = Arrays.asList("A", "B"); Collections.unmodifiableList才安全) - 为“方便测试”把本该
private的方法改成package-private,又没加@VisibleForTesting注释——测试成了绕过封装的后门
封装最难的部分不是语法,而是每次加一个 public 方法前,得想清楚:这个接口是否真的需要暴露?它的输入边界在哪?输出是否可控?一旦松动,后续所有调用都绑死在这个契约上,改起来比重构字段还疼。









