用好访问修饰符的关键是让变化有边界、依赖有方向:优先private+节制public,用行为方法替代setter,构造时初始化有效状态;慎用protected,倾向策略接口而非继承;default包级访问强化模块内聚;sealed类主动约束继承范围。

用好访问修饰符的关键,不是把东西“锁死”,而是让变化有边界、依赖有方向。过度设计往往源于过早暴露或过早隐藏——比如把所有字段设为 public,或反过来,一律 private 加一堆 getter/setter,反而制造了隐式耦合。
优先用 private + 有节制的 public 方法
类的内部状态默认应是私有的,这是封装的起点。但更重要的是:只暴露真正需要被外部调用的行为,而不是暴露字段或实现细节。
- 避免为每个 private 字段配一个 public setter——这等于把校验逻辑和状态变更权交给了调用方
- 用行为方法替代属性访问:比如
applyDiscount(0.1)比setDiscountRate(0.1)更安全,因为前者可在内部检查是否允许打折、是否已过期等 - 构造时就完成有效状态初始化,减少后续修改需求
protected 要谨慎,别把它当“预留扩展口”
protected 看似灵活,实则常成为紧耦合的温床。子类一旦依赖父类的 protected 方法,就绑定了父类的具体实现逻辑。
- 如果某个方法预期被子类重写,应在文档中明确说明意图,并考虑用模板方法模式+ final 钩子方法来约束调用顺序
- 避免在父类里写
protected void calculateScore()却没说明它和validate()的执行前提关系,否则子类重写后可能绕过校验 - 更稳妥的做法是:把可变逻辑抽成接口,由子类注入策略,而非继承覆写
包级访问(default)是天然的解耦层
Java 默认访问权限不是“没写”,而是一种有意的设计信号:这些成员只服务于当前包内的协作类,不对外承诺稳定性。
- 把一组高内聚的类放在同一包下,用 default 修饰工具方法、辅助类或构建器,外部模块完全感知不到它们的存在
- 比起用 public + 注释“仅供内部使用”,default 是编译器强制的契约,杜绝误用
- 配合模块系统(module-info.java),还能进一步限制包导出范围,形成双重隔离
密封类(sealed)主动收口继承面
当确实需要继承时,用 sealed 替代开放继承,把“谁可以扩展我”从运行时约定变成编译期约束。
- 声明
sealed abstract class Shape permits Circle, Rectangle, Triangle,就杜绝了第三方随意新增形状实现带来的不可控分支 - 每个许可子类再按需选择
final(如Circle)、sealed(如Rectangle下再分RoundRectangle)、或non-sealed(仅对特定场景开放) - 这样既保留了多态能力,又避免了继承树失控导致的维护成本和测试爆炸
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











