封装核心是控制访问路径:字段必须private,setter须校验输入,getter应返回不可变副本,可变引用需防御性拷贝,不可为框架牺牲校验逻辑。

封装不是加个 private 就算完事,核心在于“控制访问路径”——既要隐藏内部状态,又要确保所有外部修改都经过校验,所有外部读取都不破坏内部一致性。
字段必须私有,且禁止裸露可变对象引用
所有数据字段应声明为 private(不能用 protected,否则子类可绕过校验)。特别注意:对可变类型(如 List、Map、数组)必须防御性处理。
-
错误写法:
private List<String> tags;+public List<String> getTags() { return tags; }→ 外部可直接add/clear,彻底破坏封装 -
正确写法:
private final List<String> tags = new ArrayList<>();,只提供public void addTag(String tag)和public List<String> getTagsCopy() { return Collections.unmodifiableList(new ArrayList<>(tags)); } -
例外情况:像
String、LocalDateTime这类不可变类,可声明为public final,因外部无法修改其内部状态
setter 必须校验输入,拒绝非法值
每个 setter 不是简单赋值,而是第一道业务校验关卡。IDE 自动生成的 setter 默认无校验,需手动补全。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 数值范围检查:如
setAge(int age)应含if (age <= 0 || age > 150) throw new IllegalArgumentException("age must be between 1 and 150"); - 空值防御:如
setName(String name)应先判空if (name == null) throw ... - 避免全量替换方法:禁用
setUser(User u),改用细粒度、带校验的setName()、setEmail()等
getter 返回不可变副本,而非原始引用
getter 的职责是“安全交付”,不是“交出钥匙”。尤其对集合、数组、自定义可变对象。
立即学习“Java免费学习笔记(深入)”;
- 对
List<T>:返回Collections.unmodifiableList(new ArrayList<>(this.items)) - 对数组:返回
Arrays.copyOf(this.data, this.data.length) - 对自定义对象(如
Address):若非不可变,应返回新实例new Address(this.address),而非this.address
与序列化框架协同时保持封装完整性
Jackson、Hibernate 等框架需要反序列化或持久化对象,但不能为此开放 public 字段或无校验 setter。
- Jackson 推荐用
@JsonCreator+ 全参构造器,让反序列化走构造逻辑,而非 setter - Hibernate 可配合
@Access(AccessType.PROPERTY)或使用包私有字段 + public getter/setter,确保校验始终生效 - 避免为框架开后门(如加
public字段、空参构造器配@SuppressWarnings("unused"))

















