安全暴露接口的核心是守住契约边界:只公开有明确业务语义的public方法,私有化所有内部状态与实现细节,setter/getter需防御性控制,对外依赖优先使用接口而非具体实现类。

关键不是“暴露多少”,而是“暴露什么”和“怎么暴露”。安全暴露接口的核心是守住契约边界:只让外部按规则用,不给绕过逻辑的入口。
只用 public 声明有明确业务语义的方法
对外方法必须表达真实意图,而不是技术动作。比如 withdraw(double amount) 是合理接口,而 updateBalanceDirectly(double newBalance) 就不该公开——它绕过了校验、审计、状态同步等必要环节。
- 每个 public 方法都应对应一个可被业务方理解的动作,如 placeOrder()、cancelSubscription()、requestPasswordReset()
- 避免工具类方法“顺手加 public”:像 formatDate()、parseJsonString() 这类通用操作,应放在独立的工具类中,并设为 static + public;若仅服务于本类,就用 private
- 接口命名拒绝模糊词:doSomething()、handle()、process() 等缺乏上下文的方法,容易导致误用或滥用
私有化所有内部状态与实现细节
字段一律 private,连同辅助方法、缓存逻辑、状态机私有类,全部收进内部。哪怕子类需要复用,也优先通过 protected 的受控模板方法,而非开放字段或裸逻辑。
- 成员变量禁止 public 或包级可见(default);即使是 final 字段,若引用可变对象(如 ArrayList),也要做防御性复制
- 内部工具方法(如 validateEmailFormat()、buildQueryParams())设为 private,不参与任何外部契约
- 复杂行为用私有内部类封装,主类只暴露接口类型字段(如 private Iterator iterator;),调用方完全不知其实现
setter 和返回值必须做防御性控制
暴露修改能力不等于放行任意输入;暴露查询结果不等于交出内部容器引用。
立即学习“Java免费学习笔记(深入)”;
- setter 必须校验:非空、范围、格式、业务约束(如余额不能为负、订单状态只能从“待支付”转“已取消”)
- getter 若返回集合或数组,用 List.copyOf(list) 或 Collections.unmodifiableList(list),防止外部修改影响对象一致性
- 避免返回 this 或内部可变对象引用;如需链式调用,返回新实例或不可变副本
用接口或抽象类定义契约,而非具体实现类
当一组操作需被多处依赖或替换时,用 interface 或 abstract class 定义能力契约,再由私有实现类完成细节。这样既隔离变化,又防止外部直接 new 实现类破坏封装。
- 对外提供服务时,返回类型优先是接口(如 PaymentService 而非 AlipayPaymentServiceImpl)
- 工厂方法或构建器返回接口类型,内部 new 私有实现类,调用方无法感知也不需关心
- 对策略型逻辑(如不同风控规则),用多个 private static class 实现同一接口,主类根据条件返回对应实例


















