MethodHandles.Lookup 的访问权限由创建时的 lookup class 和目标成员访问修饰符共同决定,仅能访问 lookup class 自身或同包的非 private 成员,跨包 private 成员需通过 Java 9+ 的 privateLookupIn 且目标模块必须 opens 对应包。

MethodHandles.Lookup 是 Java 方法句柄机制的核心入口,它决定了你能“看到”并访问哪些类的成员(Field / Method)。它的访问能力不是无限制的,而是严格受制于**创建时的查找上下文(lookup class)** 和 **目标成员的访问修饰符**。简单说:你用哪个类去查,就受那个类的权限约束;查别人家的成员,得看人家是否“开门”。
Lookup 实例的权限由 lookup class 决定
每个 MethodHandles.Lookup 实例都绑定一个“查找类”(lookup class),通常是调用 MethodHandles.lookup() 的当前类(即隐式声明类)。这个类决定了你能合法访问哪些成员:
- 只能访问该类自身声明的 public、protected、package-private(默认)、private 成员(只要没被模块系统封锁)
- 能访问同一包内其他类的 public、protected、package-private 成员
- 不能直接访问其他包中类的 private 或 package-private 成员(即使反射能绕过,Lookup 不行)
- 跨模块时,还需满足模块导出(exports)和开放(opens)要求 —— 比如想用 Lookup 获取另一个模块中某类的 private field,目标模块必须
opens package.to.target
获取不同类成员时的典型限制与应对
想用 Lookup 获取其他类的 Field 或 Method 句柄,关键看三件事:目标类是否可访问、目标成员是否可见、当前 Lookup 是否有足够权限。
-
访问同包非 private 成员:直接用
lookup.findGetter/Setter/StaticSetter/StaticGetter或findVirtual/findStatic即可,无需额外操作 -
访问其他包的 public 成员:可以,但仅限 public;例如
lookup.findVirtual(String.class, "length", MethodType.methodType(int.class))合法 -
访问其他类的 private 成员:不行 —— 除非你用的是该类自身的 Lookup(即在目标类内部调用
MethodHandles.lookup()),或通过MethodHandles.privateLookupIn(targetClass, lookup)(Java 9+)申请私有访问权(前提是模块允许 opens) -
突破限制的常见误区:试图用
MethodHandles.lookup().in(otherClass)并不能提升权限,这只改变后续查找的“名义上下文”,不改变原始 Lookup 的权限基础
Java 9+ 的 privateLookupIn 是关键突破口
如果确实需要从外部获取某个类的 private 成员句柄(比如做高性能字段读写),且目标类所在模块已开放对应包(opens com.example.foo),可使用:
立即学习“Java免费学习笔记(深入)”;
Lookup targetLookup = MethodHandles.privateLookupIn(TargetClass.class, callerLookup);
其中 callerLookup 是你当前拥有的、有权限调用 privateLookupIn 的 Lookup(通常是本类的 lookup)。这个操作会返回一个新 Lookup,它拥有对 TargetClass 私有成员的访问权 —— 但仅限于 TargetClass 自身声明的 private 成员,不递归授权其父类或内部类。
- 失败时抛
IllegalAccessException,常见原因:目标模块未 opens、目标类是 final、目标成员是 native 或不存在 - 注意:即使成功,也不能用它访问其他类的 private 成员,权限严格限定在指定 targetClass 范围内
Field 和 Method 句柄获取的典型方法对照
不同访问场景对应不同查找方法,选错就会抛异常:
-
实例字段读取:
lookup.findGetter(Owner.class, "fieldName", fieldType) -
实例字段写入:
lookup.findSetter(Owner.class, "fieldName", fieldType) -
静态字段读取:
lookup.findStaticGetter(Owner.class, "STATIC_FIELD", fieldType) -
实例方法调用:
lookup.findVirtual(Owner.class, "methodName", methodType)(非 private)或targetLookup.findSpecial(...)(private,需 targetLookup) -
构造器句柄:
lookup.findConstructor(Target.class, methodType)(仅限 public 构造器;private 需privateLookupIn+findConstructor)
不复杂但容易忽略。


















