private 封装需配合校验型 getter/setter 才真正守边:getName() 脱敏空值、setAge() 校验范围、getRoles() 返回不可变副本,而非仅加 private 关键字。

用 private 隐藏内部变量,不是加个关键字就完事——关键在于它和 getter 的配合是否真正守住数据边界。只设 private 不加校验逻辑的 getter,等于锁了门却把钥匙放在门口。
private 的真实作用范围
它只限制“直接访问”,不阻止间接操作。外部代码不能写 user.age = -5,但只要提供了 getAge(),就能读;如果还提供了 setAge() 且没校验,照样能写非法值。
- private 字段只能在本类内部(含构造器、方法、getter/setter)读写
- 同包其他类、子类都不可见,也无法继承该字段
- IDE 自动生成的 getter 默认只是原样返回,不处理 null、空字符串、越界等风险
安全 getter 的设计要点
getter 不是“取值工具”,而是对外暴露的数据契约。它的职责可能远超“返回字段值”:
- 返回不可变副本:若字段是
ArrayList<string></string>,getter 应返回new ArrayList(list)或Collections.unmodifiableList(list),防止外部修改内部状态 - 延迟计算:字段本身不存在,getter 动态算出结果(如
isAdult()基于当前年份和出生年份) - 统一格式化:
getName()可自动 trim、首字母大写,避免调用方重复处理 - 敏感信息脱敏:
getIdCard()返回"110***1234"而非原始字符串
哪些字段不该配 getter
不是所有 private 字段都需要对外可读。暴露即责任,无业务意义的读取会增加维护负担:
- 纯内部缓存字段(如
private Map<string object> cache;</string>),只供本类方法使用 - 临时中间状态(如解析过程中的
private String rawJson;),生命周期短且不应被依赖 - 已通过其他方式聚合呈现的信息(如已有
getFullName(),就不必再暴露getFirstName()和getLastName())
一个典型的安全封装示例
下面这段代码展示了如何把校验、脱敏、不可变性都融入 getter:
public class User {private String name;
private int age;
private final List
public User(String name, int age) {
setName(name);
setAge(age);
}
public String getName() {
return name == null ? "" : name.trim();
}
public void setName(String name) {
if (name == null || name.trim().isEmpty()) {
throw new IllegalArgumentException("name cannot be blank");
}
this.name = name.trim();
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age 150) {
throw new IllegalArgumentException("age must be between 0 and 150");
}
this.age = age;
}
public List
return Collections.unmodifiableList(roles);
}
}

















