Java封装的核心是建立可控访问边界,需合理使用private、default、protected和public修饰符,配合校验逻辑与防御性拷贝,确保数据安全与行为约束。

Java封装的核心不是“锁住数据”,而是建立可控的访问边界。关键在于用对访问修饰符,再配合合理的访问方法设计,让外部既能安全使用,又无法绕过规则直接篡改。
private是封装的起点,不是终点
把字段声明为private只是第一步。它确保字段不能被外部类、子类或同包其他类直接读写——哪怕只是赋个值也不行。但这不等于完成封装,因为private字段一旦初始化失败或未初始化,对象就可能处于非法状态。
- 必须通过构造器或setter方法完成初始化,不能依赖外部代码“自觉”调用
- 子类无法继承private字段,也不能用super访问;想复用逻辑,得靠protected或public方法间接暴露能力
- 即使字段private,若getter返回的是可变对象(如ArrayList、Date),外部仍可能修改内部状态——这时要返回防御性拷贝
default和protected决定模块与继承的协作尺度
不加修饰符的default权限适合同一业务包内的协作。比如订单服务里Order、OrderItem、Payment三个类同属com.example.order包,它们之间可共享一些非敏感的计算逻辑或中间状态字段,但对外部包完全不可见。
protected则专为继承场景设计:父类把部分能力“有限开放”给子类,同时屏蔽无关调用者。例如一个BaseService类中定义protected void doRetry(),子类可重写或直接调用,但其他无关类连签名都看不到。
立即学习“Java免费学习笔记(深入)”;
- default字段/方法只能被同包类访问,跨包即失效,适合模块内高内聚协作
- protected字段/方法在子类中可见,无论子类是否同包;但非子类即使同包也无法访问
- 慎用protected字段——它会把子类和父类的实现细节耦合在一起,优先考虑protected方法
public接口要精简,且带校验和语义约束
public方法是外界唯一合法入口,它必须承担起数据守门人的责任。一个setAge(int)不能只做赋值,还要判断0–150范围;一个setName(String)得拒绝null或空白字符串;一个getBalance()若返回BigDecimal,应确保不暴露原始引用。
- setter中校验失败应抛出明确异常(如IllegalArgumentException),而不是静默忽略
- getter避免返回内部集合或数组的原始引用,改用
Collections.unmodifiableList()或新数组 - 不要为每个private字段机械生成getter/setter——只暴露真正需要被外部读写的属性
封装效果要能验证,不能只靠约定
光写private和getter/setter不等于封装到位。可以用几个小测试快速验证:
- 尝试在另一个包中new对象后直接访问字段——编译应报错
- 传入非法参数调用setter——运行时应抛异常,而非静默接受
- 通过getter拿到集合后尝试add元素——应抛UnsupportedOperationException
- 子类中访问父类protected成员——应成功;访问private或default(跨包)——应失败


















