必须用 private 修饰类的内部状态字段,以防止外部绕过业务逻辑篡改数据;非静态字段默认应为 private,构造器、getter/setter 和工具方法按需暴露,但字段本身不例外。
private?类的内部状态(比如字段)只要不被外部直接读写,就该默认设为 private。这不是为了“藏起来”,而是防止调用方绕过业务逻辑篡改数据。比如一个 BankAccount 类里的 balance 字段,如果公开成 public,别人就能直接写 account.balance = -1000000,跳过所有校验。
private
private 成员不可见——这是设计意图,不是限制public 方法该暴露哪些?一个方法是否该是 public,取决于它是否构成该类对外承诺的契约。比如 String.trim() 是 public,因为它是 String 类明确提供给所有调用方使用的功能;而 ArrayList 内部的 grow() 就是 private,它只服务自身扩容逻辑,换实现就可能消失。
public
public 方法public(Java 9+ 允许 private 接口方法,但那是另一回事)protected 和包级访问的模糊地带很多开发者把 protected 当作“比 private 松一点”的快捷方式,结果导致子类意外依赖父类实现细节。更常见的是误用包级访问(即不写修饰符),以为“同包内安全”,实际却让测试类、工具类、甚至未来新增的同包子类轻易穿透封装边界。
protected 应仅用于明确支持继承扩展的钩子方法(如 Swing 组件的 paintComponent())public
的委托方法,也不开放 protected 字段IntelliJ 自动生成 getter/setter 时,默认生成 public 方法,但不会提醒你:这个字段真需要被外部修改吗?Lombok 的 @Data 更危险——它一键生成所有 public getter/setter,等于把所有字段都“合法裸奔”。曾经有项目用 @Data 修饰 DTO,结果前端传个负数 ID,后端毫无感知地存进数据库。
public class Order {
private Long id; // ✅ 应保持 private
private BigDecimal total; // ✅ 同上
// ❌ @Data 会自动生成 public void setTotal(BigDecimal t),但 total 应由业务方法计算得出
}
@Getter + 手动写业务 setter,或用 @Accessors(fluent = true) 配合私有化public 接口,而不是反射访问 private 字段——后者是在测试实现,不是测试行为