在 Java 开发中,我们经常会把成员变量定义成private:
classUser{privateStringname="Tom";}这时候很多初学者都会有疑问:
private不是只能类内部访问吗?- 在类外面还能获取吗?
- 为什么 Spring、MyBatis 等框架还能读取私有属性?
答案就是:Java 反射(Reflection)。
一、什么是 private?
private是 Java 的访问修饰符,表示只能在当前类内部访问。
例如:
classUser{privateStringname="Tom";}下面这样访问会直接报错:
Useruser=newUser();System.out.println(user.name);编译器提示:
name has private access in User这是因为private限制了外部直接访问。
二、如何获取 private 成员?
Java 提供了反射机制。
例如:
importjava.lang.reflect.Field;classUser{privateStringname="Tom";}publicclassTest{publicstaticvoidmain(String[]args)throwsException{Useruser=newUser();Fieldfield=User.class.getDeclaredField("name");field.setAccessible(true);Stringvalue=(String)field.get(user);System.out.println(value);}}运行结果:
Tom即使name是private,依然可以读取。
三、为什么可以访问 private?
关键就在这一句:
field.setAccessible(true);它的作用是:
关闭 Java 的访问权限检查。
正常情况下:
private ↓ 不能访问调用:
setAccessible(true)之后:
private ↓ 关闭权限检查 ↓ 可以访问因此,就能够读取甚至修改私有成员。
四、还能修改 private 成员吗?
当然可以。
例如:
Fieldfield=User.class.getDeclaredField("name");field.setAccessible(true);field.set(user,"Jack");System.out.println(field.get(user));输出:
Jack说明不仅可以读取,还可以修改私有属性。
五、为什么框架都能访问 private?
很多人第一次接触 Spring 都会疑惑:
@AutowiredprivateUserServiceuserService;既然是private,Spring 为什么还能赋值?
原因就是:
Spring 底层也是通过反射完成的。
流程大致如下:
扫描 Bean ↓ 找到 private 字段 ↓ setAccessible(true) ↓ field.set(...) ↓ 完成依赖注入MyBatis、Hibernate、Jackson 等框架也大量使用了这种方式。
六、getField() 和 getDeclaredField() 有什么区别?
这是面试中的高频追问。
例如:
Fieldfield=User.class.getField("name");如果name是private,会直接报错。
因为:
getField()只能获取 public 成员变量。
而:
Fieldfield=User.class.getDeclaredField("name");可以获取:
- private
- protected
- 默认(package)
- public
所有成员变量。
因此:
访问私有字段时,一般使用
getDeclaredField()。
七、面试如何回答?
如果面试官问:
Java 如何获取 private 成员变量?
可以这样回答:
Java 可以通过反射获取私有成员变量。首先使用
getDeclaredField()获取字段对象,再调用setAccessible(true)关闭 Java 的访问权限检查,最后通过field.get()获取值,或使用field.set()修改值。Spring、MyBatis 等框架底层也大量使用这种反射机制来访问和注入私有成员。
八、总结
记住下面四句话即可:
private成员默认只能在类内部访问。- 反射可以突破访问限制,访问 private 成员。
- 访问私有字段通常使用
getDeclaredField()。 - 调用
setAccessible(true)后,就可以读取或修改私有成员。
一句话总结:Java 获取私有成员的核心就是反射,通过
getDeclaredField()获取字段,再调用setAccessible(true)关闭访问检查,从而读取或修改private成员,这也是 Spring、MyBatis 等框架底层常用的实现方式。