Java成员变量访问权限需按协作边界系统设计:private需配校验逻辑,default适用于包内高内聚协作,protected慎用字段而优先方法,public接口须精简且防御性返回。

Java成员变量的访问权限不是随便选的,关键看它该被谁用、怎么用。封装不是把所有字段都设成private就完事,而是围绕数据安全和协作边界做系统设计。
private是起点,但必须配校验逻辑
声明private只是锁住直接访问,不代表数据自动安全。比如年龄字段设为private int age,若只靠setAge(int)简单赋值,外部仍可传入-5或200这种非法值。
- 所有
setter方法都要做参数校验:范围检查、非空判断、格式验证 - 校验失败抛出明确异常,如
IllegalArgumentException("age must be between 0 and 150") - 构造器里也要校验,避免对象一创建就处于非法状态
default适合模块内高内聚协作
不加修饰符的default权限,天然适用于同一业务包内的类协作。比如订单模块中Order、OrderItem、Payment都在com.example.order包下,它们之间可以共享一些中间计算字段或工具方法,但对外部包完全不可见。
- 跨包调用时,
default成员直接不可见,编译报错 - 比
public更轻量,比private更灵活,适合内部解耦 - 不要为了“方便”把本该
private的字段改成default
protected要慎用字段,优先暴露方法
protected让子类能访问,但也意味着父类实现细节会泄漏。如果父类有个protected List<String> tags,子类可能直接修改这个列表,破坏父类状态一致性。
立即学习“Java免费学习笔记(深入)”;
- 尽量用
protected方法代替protected字段,比如protected void addTag(String tag) - 若必须暴露集合类字段,getter返回不可修改视图:
Collections.unmodifiableList(tags) - 子类不该依赖父类字段名或类型,而应通过受控方法交互
public接口必须精简且带语义约束
一个类对外只该暴露真正需要的public方法,每个方法都是数据守门人。
- 不要为每个
private字段机械生成getter/setter——只暴露业务上确实要读写的属性 - 返回可变对象(如
ArrayList、Date)时,必须做防御性拷贝或返回不可修改包装 -
getBalance()返回BigDecimal,不能返回原始引用;getName()拒绝null或空白字符串


















