private属性仅限本类内部访问,子类和同包类均不可访问,其限制依据是声明位置而非调用位置;getter/setter是唯一合法访问途径,用于公开行为而非暴露实现。

private 属性只能被本类的代码访问,连子类和同包类都不行
这是最常被误读的一点:很多人以为 private 只是“不让外部直接用”,其实它连继承链都严格切断。哪怕子类在同一个文件里、甚至写在父类内部作为嵌套类,只要不是同一个 class 的花括号范围内,就不能碰那个 private 字段或方法。
常见错误现象:
- 子类中写
this._id报错:error CS0122: '_id' is inaccessible due to its protection level - 同包下另一个类尝试访问
new BankAccount()._balance,编译直接失败 - 反射强行读取
field.setAccessible(true)能绕过,但这属于破坏封装,不是设计意图
关键判断依据是「声明位置」而非「调用位置」——只要不是定义它的那个 class 主体内部,一律拒绝。
getter/setter 不是绕过 private,而是它唯一合法的出口
private 从不阻止你暴露能力,只阻止你暴露实现。所以你写 public String getName(),本质是把“读取名字”这个行为公开,而不是把 _name 这个变量公开。
实操建议:
- 不要为了省事把字段设为
public,哪怕只是临时调试;一旦发布,改回private就会破坏所有调用方 - setter 里加校验逻辑(比如
if (age ),这是 <code>private+public方法组合的价值所在 - 如果字段本身是
final或readonly,且只在构造时赋值,那 getter 就是纯转发,没副作用
嵌套类可以访问外围类的 private 成员,但反过来不行
这是容易忽略的例外:一个 class A 里定义的 class B(即非静态内部类),能直接读写 A 的 private 字段;但 A 不能直接访问 B 的 private 成员,除非通过 B 暴露的 public 方法。
示例片段:
class Outer {
private int x = 42;
class Inner {
void printX() { System.out.println(x); } // ✅ 合法:Inner 可访问 Outer 的 private
}
}
// Outer 中不能写 new Inner().x —— ❌ 编译报错
这种单向穿透是语言设计的特例,不是漏洞。它服务于“内部类作为主体类的延伸”这一语义,但不会影响模块边界。
private 不等于“不可见”,而是“不可直达”
很多初学者看到 IDE 对 private 成员标灰、补全不出现,就以为它彻底消失了。其实它在字节码/CIL 层面完全存在,JVM/.NET 运行时也照常加载。限制只发生在编译期检查阶段。
这意味着:
- 序列化框架(如 Jackson、System.Text.Json)默认无法处理
private字段,需显式配置setAccessible(true)或用注解标记 - 单元测试里可以直接 new 出对象,然后用反射读写
private字段做白盒验证——这反而是合理用法 - 混淆工具(ProGuard/R8)会重命名
private字段,因为它们本就不该被外部引用,重命名无兼容风险
真正难处理的,是那些本该 private 却被意外暴露成 public 的字段——等发现时,API 已经被下游依赖,再改就牵一发而动全身。










