核心是让方法只对真正需要它的代码可见——不是靠信任,而是靠编译器和运行时的强制拦截;优先用private收窄入口,protected需配套契约文档,public只暴露稳定业务契约,default限于模块内协作并警惕包名冲突。

核心是让方法只对真正需要它的代码可见——不是靠信任,而是靠编译器和运行时的强制拦截。可见性设得越宽,越容易被误用、滥用或绕过业务逻辑。
优先用 private,把入口收窄到最小范围
绝大多数工具方法、状态校验逻辑、内部状态变更操作,都不该被外部触碰。声明为 private 后,连同包类、子类、反射(默认情况下)都无法直接调用,从源头切断非法路径。
- 字段初始化辅助方法、JSON 序列化前的数据清洗逻辑、密码哈希计算封装——这些都该是 private
- 避免“先 public 再改 private”的惯性:一旦暴露,下游可能已形成强依赖,后续收缩会引发编译失败或运行时异常
- private 方法可自由重构参数、重命名、拆分合并,不影响任何外部代码
子类扩展点慎用 protected,必须配套契约文档
protected 不是“给子类用的快捷通道”,而是明确开放继承契约的信号。它允许跨包子类访问,风险远高于 package-private。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 禁止仅因“以后可能要继承”就提前设为 protected;没有当前继承需求,一律用 private 或 default
- 若确需 protected 方法(如模板方法中的钩子),必须在 Javadoc 中写清:输入约束(如“不允许 null”)、是否线程安全、是否有副作用(如修改共享状态)、是否允许重入
- 更安全的替代:用 abstract 方法 + final 模板方法,把流程控制权完全交给父类,子类只能实现规定动作,无法跳过校验或乱序调用
对外暴露接口用 public,但只暴露契约,不暴露实现
public 方法是类与外界的正式协议,它的签名和行为必须稳定。不要因为“方便调试”或“临时支持”而加 public 工具方法。
- 所有 public 方法必须有明确业务语义(如
withdraw(double amount)),而非技术动作(如updateBalanceDirectly(double newBalance)) - 拒绝裸字段 setter:
setBalance()必须校验金额非负、不超信用额度、触发审计日志;若允许绕过规则,说明设计本身已失守 - 返回值做防御性复制:public 方法若返回集合或数组,用
Collections.unmodifiableList()或List.copyOf(),防止外部修改影响内部状态
包内协作用默认权限(package-private),但警惕模块边界失效
default 权限适合同一业务模块内的类协同,比如 DAO 层与实体类之间、策略实现与上下文之间的调用。但它不防同名包的“伪同包”访问。
- Maven 多模块项目中,不同 module 若声明相同 package,它们能互相访问 default 成员——这不是设计意图,而是 classloader 的妥协
- JDK 9+ 环境下,应配合
module-info.java使用:exports com.example.core;仅导出 API 包,com.example.internal包不 exports,即使类是 public,其他模块也无法 import 或 new - JDK 8 及以下,可用静态工厂 + 接口返回 + 私有实现类组合:工厂方法是 public,但返回的是 interface,具体 class 设为 package-private 或 private static class,外部连类名都拿不到
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










