private仅限声明它的那个类的{}内访问,编译期强制限制;子类、同包类、甚至同一文件中其他类均不可直接访问,必须通过public getter/setter等契约接口间接操作。

private 的“类内部”不是指“同一个文件”或“同包”,而是严格限定在 声明它的那个 class 的花括号 {} 范围内。超出这个范围,哪怕只是多了一层嵌套、换了一个类名、甚至子类就写在同一个 Java 文件里,都不算“内部”。
关键判断依据是声明位置,不是调用位置
编译器只看:访问语句所在的代码,是否属于该 private 成员被定义的那个 class 主体。
- ✅ 合法:class A 中的普通方法、构造器、静态块、非静态块、内部类(非 static)里的代码,都可以直接读写 A 的 private 字段和方法
- ❌ 非法:class B(无论是否继承 A、是否同包、是否在同一文件)中的任何代码,都不能直接访问 A.privateField
- ⚠️ 特例:A 中定义的非静态内部类 B,能访问 A 的 private 成员;但 A 不能直接访问 B 的 private 成员(除非 B 提供 public 方法)
它不是“隐藏”,而是“禁止直达”
private 字段在字节码里完整存在,JVM 运行时也照常加载。限制只发生在编译阶段——IDE 不提示、编译器报错 CS0122 或类似错误,都是编译期检查的结果。
- 反射可通过
setAccessible(true)绕过,但这违背封装设计初衷 - 序列化框架(如 Jackson)默认跳过 private 字段,需注解或配置显式启用
- 字段可见性 ≠ 不存在,只是语言强制你走公开接口
getter/setter 不是妥协,而是设计契约
提供 public String getName(),不是为了“让外面拿到 _name”,而是把“获取名字”这个行为标准化、可管控。
- setter 可加校验逻辑(比如年龄不能为负)
- getter 可返回计算值、克隆副本、或延迟初始化结果
- 字段本身可以是 final,构造后不可变,getter 就是安全转发
- 不暴露实现细节,意味着未来可把 String name 改成 NameObject name,而对外接口不变
常见误读与实际表现
很多人以为“子类能继承 private 成员”,其实子类根本看不到它们——既不参与继承链,也不出现在子类的成员列表中。
- 子类中写
this._id→ 编译报错:“_id is inaccessible due to its protection level” - 同包另一个类写
new BankAccount()._balance→ 编译失败,不看包,只看 class - 把字段临时改成 public 调试?上线前改回 private 会直接破坏所有外部直访问代码
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











