MethodHandles.Lookup 类

定义

<当创建需要访问检查时,em>lookup 对象</em> 是用于创建方法句柄的工厂。

[Android.Runtime.Register("java/lang/invoke/MethodHandles$Lookup", ApiSince=26, DoNotGenerateAcw=true)]
public sealed class MethodHandles.Lookup : Java.Lang.Object
[<Android.Runtime.Register("java/lang/invoke/MethodHandles$Lookup", ApiSince=26, DoNotGenerateAcw=true)>]
type MethodHandles.Lookup = class
    inherit Object
继承
MethodHandles.Lookup
属性

注解

<当创建需要访问检查时,em>lookup 对象</em> 是用于创建方法句柄的工厂。 方法句柄在调用时不执行访问检查,而是在创建方法句柄时执行访问检查。 因此,创建方法句柄时必须强制实施方法句柄访问限制。 对其强制实施这些限制的调用方类称为 #lookupClass 查找类。

需要创建方法句柄的查找类将调用 #lookup MethodHandles.lookup 以为自己创建工厂。 Lookup创建工厂对象时,将确定查找类的标识,并安全地存储在 对象中Lookup。 然后,查找类 (或其委托) 可以在 对象上使用 Lookup 工厂方法为访问检查的成员创建方法句柄。 这包括允许用于查找类的所有方法、构造函数和字段,甚至是私有方法。

<h1>“lookups”>Lookup Factory Methods</h1> 对象上的 Lookup 工厂方法对应于方法、构造函数和字段的所有主要用例。 工厂方法创建的每个方法句柄都是特定 <em>字节码行为</em> 的功能等效项。 (Bytecode 行为在 Java 虚拟机规范的第 5.4.3.5 节中介绍。) 下面是这些工厂方法与结果方法处理的行为之间的对应关系的摘要:<table border=1 cellpadding=5 summary=“lookup method behaviors”><tr<>th>“equiv”>lookup expression</th<>>th member</th><th>th bytecode behavior</th<>/tr<<>>td>java.lang.invoke.MethodHandles.Lookup#findGetter lookup.findGetter(C.class,"f",FT.class)</Td><td>FT f;</td><td>(T) this.f;</><tr td/td><>>java.lang.invoke.MethodHandles.Lookup#findStaticGetter lookup.findStaticGetter(C.class,"f",FT.class)><<< tdstatic><brFT f;></td td/td><td<(T) C.f;>/td<>/tr>><<td>java.lang.invoke.MethodHandles.Lookup#findSetter lookup.findSetter(C.class,"f",FT.class)</td></td td><FT f;/td></tr td<>this.f = x;/td<>/tr>><<td<java.lang.invoke.MethodHandles.Lookup#findStaticSetter lookup.findStaticSetter(C.class,"f",FT.class)>/td><>static<>FT f;<><Td>C.f = arg;</td></tr><tr><td>java.lang.invoke.MethodHandles.Lookup#findVirtual lookup.findVirtual(C.class,"m",MT)</td><td>T m(A*);</td><td>(T) this.m(arg*);</td></tr><<>td<java.lang.invoke.MethodHandles.Lookup#findStatic lookup.findStatic(C.class,"m",MT)>/td><td<static>brT m(A*);></td td><<(T) C.m(arg*);>/td></tr<>><td/td/tdT m(A*);>><(T) super.m(arg*);<><> td>java.lang.invoke.MethodHandles.Lookup#findSpecial lookup.findSpecial(C.class,"m",MT,this.class)<</Td></tr><<>tdjava.lang.invoke.MethodHandles.Lookup#findConstructor lookup.findConstructor(C.class,MT)<>/td><td>C(A*);</td><tdnew C(arg*);<>/td<>/tr td/tr<>><tdjava.lang.invoke.MethodHandles.Lookup#unreflectGetter lookup.unreflectGetter(aField)></td><> (static) ?<br>FT f;</td><td>(FT) aField.get(thisOrNull);</tr td></tr><><td>java.lang.invoke.MethodHandles.Lookup#unreflectSetter lookup.unreflectSetter(aField)</td>>< (static) ?<br><FT f;/td><td><aField.set(thisOrNull, arg);/td></tr>><<td<java.lang.invoke.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)>/td><td> (static) ?<br><T m(A*);/td><td>(T) aMethod.invoke(thisOrNull, arg*);</td></tr><><td>java.lang.invoke.MethodHandles.Lookup#unreflectConstructor lookup.unreflectConstructor(aConstructor)</td><td<C(A*);>/td><td/td<>(C) aConstructor.newInstance(arg*);></tr td></tr><tdjava.lang.invoke.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)></td><> (static) ?<br><T m(A*);/td><td><(T) aMethod.invoke(thisOrNull, arg*);/td></tr></table>

在这里,类型 C 是正在搜索成员的类或接口,在查找方法中记录为名为 refc 的参数。 方法类型 MT 由返回类型和 T 参数类型的 A*序列组成。 构造函数还具有一系列参数类型 A* ,被视为返回类型 C为 的新创建的对象。 MT和 字段类型FT都记录为名为 的参数type。 正式参数 this 代表 类型的 C自引用;如果存在,则它始终是方法句柄调用的前导参数。 (对于某些 protected 成员, this 可能仅限于查找类的类型;请参阅下文。) 名称 arg 代表所有其他方法句柄参数。 在核心反射 API 的代码示例中,如果访问的方法或字段是静态的,则名称 thisOrNull 代表 null 引用, this 否则为 null 引用。 名称 aMethodaFieldaConstructor 代表对应于给定成员的反射对象。

如果给定成员是变量 arity (,则返回的方法句柄) 方法或构造函数也将是 MethodHandle#asVarargsCollector 变量 arity。 在所有其他情况下,返回的方法句柄将是固定的。 <p style=“font-size:smaller;”><em>Discussion:</em> looked-up 方法句柄和基础类成员与字节码行为之间的等效性可以通过以下几种方式分解:<ul style=“font-size:smaller;”><如果>C无法通过查阅类的加载程序进行符号访问,则即使没有等效的 Java 表达式或字节编码常量,查找仍可以成功。 <>同样,如果 TMT 无法从查阅类的加载程序进行符号访问,则查找仍可以成功。 例如,无论请求的类型如何,查找 MethodHandle.invokeExactMethodHandle.invoke 将始终成功。 <li>如果安装了安全管理器,则可以以各种理由禁止查找, (请参阅以下) 。 相比之下, ldc 常量上的 CONSTANT_MethodHandle 指令不受安全管理器检查的影响。 <li>如果查找方法具有非常大的余量,则方法句柄创建可能会失败,因为方法句柄类型具有太多参数。 </ul>

<h1>“access”>访问检查</h1> 创建方法句柄时,将在 的 Lookup工厂方法中应用访问检查。 这是与核心反射 API 的主要区别,因为 java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke 每次调用时都会针对每个调用方执行访问检查。

所有访问检查都从 对象 Lookup 开始,该对象将其记录的查阅类与创建方法句柄的所有请求进行比较。 单个 Lookup 对象可用于创建任意数量的访问检查方法句柄,所有这些句柄都针对单个查找类进行检查。

Lookup对象可以与其他受信任的代码(例如元对象协议)共享。 共享 Lookup 对象委托在查阅类的私有成员上创建方法句柄的功能。 即使特权代码使用 Lookup 对象,访问检查也仅限于原始查找类的权限。

查找可能会失败,因为查阅类无法访问包含类,或者缺少所需的类成员,或者查找类无法访问所需的类成员,或者因为查阅对象不够受信任,无法访问该成员。 在上述任何情况下, ReflectiveOperationException 都将从尝试的查找中引发 。 确切类将是以下类之一:ul>li NoSuchMethodException —如果请求了某个方法,但不存在 <li>NoSuchFieldException —如果请求了字段,但不存在 <li>IllegalAccessException —如果该成员存在,但访问检查失败 </ul><<>

一般情况下,查找方法句柄 M 的条件并不比查找类编译、验证和解析对 M的调用的条件严格。 其中 JVM 会引发类似 的 NoSuchMethodError异常,方法句柄查找通常会引发相应的选中异常,例如 NoSuchMethodException。 并且调用查找产生的方法句柄的效果与执行对 的已编译、已验证和已解析的调用 M完全等效。 字段和构造函数的点相同。 <p style=“font-size:smaller;”><em>Discussion:</em> Access 检查仅适用于命名和反映的方法、构造函数和字段。 其他方法句柄创建方法(如 MethodHandle#asType MethodHandle.asType)不需要任何访问检查,并且独立于任何 Lookup 对象使用。

如果所需成员为 protected,则应用通常的 JVM 规则,包括要求查找类必须与所需成员位于同一个包中,或者必须继承该成员。 (请参阅 Java 虚拟机规范第 4.9.2、5.4.3.5 和 6.4.) 此外,如果所需成员是其他包中的非静态字段或方法,则生成的方法句柄只能应用于查阅类或其子类之一的对象。 此要求是通过将前导参数的类型从 C (前导this参数的类型缩小,该参数必然是查找类) 查找类本身的超类来实现的。

JVM 对 invokespecial 指令施加了类似的要求,即接收方参数必须与解析的方法 <em>和</em> 匹配当前类。 同样,通过将前导参数的类型缩小为生成的方法句柄来强制实施此要求。 (请参阅 Java 虚拟机规范第 4.10.1.9.) 节

JVM 将构造函数和静态初始值设定项块表示为具有特殊名称的内部方法 ("<init>""<clinit>") 。 调用指令的内部语法允许它们引用此类内部方法,就像它们是普通方法一样,但 JVM 字节码验证程序拒绝它们。 查找此类内部方法将生成 NoSuchMethodException

在某些情况下,Java 编译器通过创建包装方法来访问同一顶级声明中另一个类的私有方法,从而获得嵌套类之间的访问。 例如,嵌套类 C.D 可以访问其他相关类(如 CC.D.EC.B)中的私有成员,但 Java 编译器可能需要在这些相关类中生成包装方法。 在这种情况下, Lookup 上的 C.E 对象将无法用于这些私有成员。 此限制的解决方法是 Lookup#in Lookup.in 方法,该方法可以将查找转换为任何其他类上的查找 C.E ,而无需特殊特权提升。

根据给定查找对象的集 #lookupModes lookupModes,允许对给定查找对象的访问可能会限制为通常可供查阅类访问的成员子集。 例如, #publicLookup publicLookup 方法生成一个查阅对象,该对象仅允许访问公共类中的公共成员。 调用方敏感方法 #lookup lookup 生成具有相对于其调用方类的完整功能的查找对象,以模拟所有受支持的字节代码行为。 此外, Lookup#in Lookup.in 方法可能会生成访问模式比原始查找对象少的查找对象。

<p style=“font-size:smaller;”>privacc“><em>讨论专用访问:</em> 我们说,如果查找 #lookupModes 查找模式包括访问private成员的可能性,则查找具有 <>em private access</em>。 如其他位置的相关方法中所述,只有具有专用访问权限的查找才具有以下功能:<ul style=“font-size:smaller;”><li>访问查找类<的私有字段、方法和构造函数 li>create 方法句柄,该方法调用调用方敏感方法,如<Class.forName li>create 方法处理哪些Lookup#findSpecial emulate invokespecial指令 <li>避免包访问检查查找类 <li>create Lookup#in delegated lookup objects 可访问的类,这些类对同一包成员 </ul><p style=“font-size:smaller;”>其中每个权限都是这样一个事实的结果,即具有专用访问权限的查找对象可以安全地追溯到原始类,其字节代码行为和 Java 语言访问权限可以通过方法句柄可靠地确定和模拟。

<h1>“secmgr”>安全管理器交互</h1> 尽管字节代码指令只能引用相关类加载程序中的类,但只要对其对象的引用 Class 可用,此 API 就可以在任何类中搜索方法。 此类交叉加载程序引用也可用于核心反射 API,并且无法字节代码指令(如 invokestaticgetfield)。 有一个 java.lang.SecurityManager 安全管理器 API,允许应用程序检查此类跨加载程序引用。 这些检查适用于 MethodHandles.Lookup API 和核心反射 API (,如) 上所示 java.lang.Class Class

如果存在安全管理器,则成员查找会受到其他检查。 对安全管理器进行一到三次调用。 这些调用中的任何调用都可以通过引发 java.lang.SecurityException SecurityException来拒绝访问。 定义为 smgr 安全管理器、 lookc 当前查找对象的查阅类、 refc 要在其中查找成员的包含类,以及 defc 实际定义成员的类。 如果当前查找对象没有专用访问权限,则该值 lookc 定义为 <em>not present</em> 。 调用根据以下规则进行:ul>li b 步骤 1:</b> 如果lookc不存在,或者如果其类加载程序与 或 类加载程序的refc上级不同,则SecurityManager#checkPackageAccess smgr.checkPackageAccess(refcPkg)调用 ,其中 refcPkg 是 的refc包。>><<< <li><b>步骤 2:</b> 如果检索到的成员不是公共成员且 lookc 不存在,则 SecurityManager#checkPermission smgr.checkPermission 使用 RuntimePermission("accessDeclaredMembers") 调用 。 <li><b>步骤 3:</b> 如果检索到的成员不是公共成员,如果 lookc 不存在,并且 defcrefc 不同,则 SecurityManager#checkPackageAccess smgr.checkPackageAccess(defcPkg) 调用 ,其中 defcPkg 是 的 defc包。 </ul> 安全检查在通过其他访问检查后执行。 因此,上述规则假定成员为公共成员,或者从有权访问该成员的查阅类访问该成员。

<h1>“callens”>调用方敏感方法</h1> 少数 Java 方法具有称为调用方敏感度的特殊属性。 em <>调用方敏感</em> 方法的行为可能会有所不同,具体取决于其直接调用方的身份。

如果请求调用方敏感方法的方法句柄,则适用字节代码行为的一般规则,但它们以特殊方式考虑查找类。 生成的方法句柄的行为就像是从查阅类中包含的指令调用的,以便调用方敏感的方法检测查找类。 (相比之下,方法句柄的调用程序被忽略。) 因此,对于调用方敏感的方法,不同的查找类可能会产生不同的行为方法句柄。

如果 lookup 对象为 #publicLookup publicLookup(),或者没有专用访问的其他某个查找对象,则忽略查找类。 在这种情况下,无法创建对调用方敏感的方法句柄,禁止访问,并且查找失败并出现 IllegalAccessException。 <p style=“font-size:smaller;”><em>Discussion:</em> 例如,调用方敏感方法 java.lang.Class#forName(String) Class.forName(x) 可以返回不同的类或引发不同的异常,具体取决于调用它的类的类加载程序。 的公共查找 Class.forName 将失败,因为没有合理的方法来确定其字节码行为。 <p style=“font-size:smaller;”> 如果应用程序缓存方法句柄以便进行广泛共享,则应使用 publicLookup() 来创建它们。 如果查找 Class.forName,它将失败,在这种情况下,应用程序必须采取适当的操作。 以后的查找(可能在启动方法调用期间)可以合并调用方的特定标识,使方法可访问。 <p style=“font-size:smaller;”> 该函数 MethodHandles.lookup 对调用方敏感,因此可以有一个安全的基础进行查找。 JSR 292 API 中的几乎所有其他方法都依赖于查找对象来检查访问请求。

java.lang.invoke.MethodHandles.LookupJava 文档。

此页面的部分内容是基于 创建和共享的工作进行的修改,并根据 署名许可中所述的术语使用。

字段

Package
已过时.

表示 package 访问 (默认访问) 的单位掩码,这可能会导致 的结果 #lookupModes lookupModes

Private
已过时.

表示 private 访问的单位掩码,这可能会导致 的结果 #lookupModes lookupModes

Protected
已过时.

表示 protected 访问的单位掩码,这可能会导致 的结果 #lookupModes lookupModes

Public
已过时.

表示 public 访问的单位掩码,这可能会导致 的结果 #lookupModes lookupModes

属性

Class

返回此 Object的运行时类。

(继承自 Object)
Handle

基础 Android 实例的句柄。

(继承自 Object)
JniIdentityHashCode

<当创建需要访问检查时,em>lookup 对象</em> 是用于创建方法句柄的工厂。

(继承自 Object)
JniPeerMembers

<当创建需要访问检查时,em>lookup 对象</em> 是用于创建方法句柄的工厂。

PeerReference

<当创建需要访问检查时,em>lookup 对象</em> 是用于创建方法句柄的工厂。

(继承自 Object)
ThresholdClass

此 API 支持 Mono for Android 基础结构,不应直接从代码使用。

(继承自 Object)
ThresholdType

此 API 支持 Mono for Android 基础结构,不应直接从代码使用。

(继承自 Object)

方法

Bind(Object, String, MethodType)

为非静态方法生成早期绑定的方法句柄。

Clone()

创建并返回此对象的副本。

(继承自 Object)
Dispose()

<当创建需要访问检查时,em>lookup 对象</em> 是用于创建方法句柄的工厂。

(继承自 Object)
Dispose(Boolean)

<当创建需要访问检查时,em>lookup 对象</em> 是用于创建方法句柄的工厂。

(继承自 Object)
Equals(Object)

指示其他某个对象是否“等于”此对象。

(继承自 Object)
FindConstructor(Class, MethodType)

生成一个方法句柄,该方法使用指定类型的构造函数创建对象并对其进行初始化。

FindGetter(Class, String, Class)

生成一个方法句柄,授予对非静态字段的读取访问权限。

FindSetter(Class, String, Class)

生成一个方法句柄,授予对非静态字段的写入访问权限。

FindSpecial(Class, String, MethodType, Class)

为虚拟方法生成早期绑定的方法句柄。

FindStatic(Class, String, MethodType)

为静态方法生成方法句柄。

FindStaticGetter(Class, String, Class)

生成一个方法句柄,授予对静态字段的读取访问权限。

FindStaticSetter(Class, String, Class)

生成一个方法句柄,授予对静态字段的写入访问权限。

FindStaticVarHandle(Class, String, Class)

生成一个 VarHandle,授予对 类型为 type 的类中声明的decl静态字段name的访问权限。

FindVarHandle(Class, String, Class)

生成一个 VarHandle,授予对 类型type为 的类中声明的非recv静态字段name的访问权限。

FindVirtual(Class, String, MethodType)

为虚拟方法生成方法句柄。

GetHashCode()

返回对象的哈希代码值。

(继承自 Object)
In(Class)

<当创建需要访问检查时,em>lookup 对象</em> 是用于创建方法句柄的工厂。

JavaFinalize()

当垃圾回收确定不再引用对象时,由对象上的垃圾回收器调用。

(继承自 Object)
LookupClass()

指示哪个类正在执行查找。

LookupModes()

告知此查找对象可以生成哪些成员的访问保护类。

Notify()

唤醒正在等待此对象的监视器的单个线程。

(继承自 Object)
NotifyAll()

唤醒正在等待此对象的监视器的所有线程。

(继承自 Object)
RevealDirect(MethodHandle)

破解此查找对象或类似对象创建的直接方法句柄。

SetHandle(IntPtr, JniHandleOwnership)

设置 Handle 属性。

(继承自 Object)
ToArray<T>()

<当创建需要访问检查时,em>lookup 对象</em> 是用于创建方法句柄的工厂。

(继承自 Object)
ToString()

返回对象的字符串表示形式。

(继承自 Object)
Unreflect(Method)

如果查阅类具有权限,则将直接方法句柄设置为 m

UnreflectConstructor(Constructor)

为反射构造函数生成方法句柄。

UnreflectGetter(Field)

生成一个方法句柄,授予对反射字段的读取访问权限。

UnreflectSetter(Field)

生成一个方法句柄,授予对反射字段的写入访问权限。

UnreflectSpecial(Method, Class)

为反射的方法生成方法句柄。

UnreflectVarHandle(Field)

生成一个 VarHandle,授予对 类型为 T 的类中声明的R反射字段f的访问权限。

UnregisterFromRuntime()

<当创建需要访问检查时,em>lookup 对象</em> 是用于创建方法句柄的工厂。

(继承自 Object)
Wait()

导致当前线程等待,直到它被唤醒,通常是通过 em <通知/em> 或 <em>interrupted</em>。<>

(继承自 Object)
Wait(Int64)

导致当前线程等待,直到它被唤醒,通常是通过 em <通知/em> 或 <em>interrupted</em>,或直到经过一定数量的实时。<>

(继承自 Object)
Wait(Int64, Int32)

导致当前线程等待,直到它被唤醒,通常是通过 em <通知/em> 或 <em>interrupted</em>,或直到经过一定数量的实时。<>

(继承自 Object)

显式接口实现

IJavaPeerable.Disposed()

<当创建需要访问检查时,em>lookup 对象</em> 是用于创建方法句柄的工厂。

(继承自 Object)
IJavaPeerable.DisposeUnlessReferenced()

<当创建需要访问检查时,em>lookup 对象</em> 是用于创建方法句柄的工厂。

(继承自 Object)
IJavaPeerable.Finalized()

<当创建需要访问检查时,em>lookup 对象</em> 是用于创建方法句柄的工厂。

(继承自 Object)
IJavaPeerable.JniManagedPeerState

<当创建需要访问检查时,em>lookup 对象</em> 是用于创建方法句柄的工厂。

(继承自 Object)
IJavaPeerable.SetJniIdentityHashCode(Int32)

<当创建需要访问检查时,em>lookup 对象</em> 是用于创建方法句柄的工厂。

(继承自 Object)
IJavaPeerable.SetJniManagedPeerState(JniManagedPeerStates)

<当创建需要访问检查时,em>lookup 对象</em> 是用于创建方法句柄的工厂。

(继承自 Object)
IJavaPeerable.SetPeerReference(JniObjectReference)

<当创建需要访问检查时,em>lookup 对象</em> 是用于创建方法句柄的工厂。

(继承自 Object)

扩展方法

JavaCast<TResult>(IJavaObject)

执行 Android 运行时检查的类型转换。

JavaCast<TResult>(IJavaObject)

<当创建需要访问检查时,em>lookup 对象</em> 是用于创建方法句柄的工厂。

GetJniTypeName(IJavaPeerable)

<当创建需要访问检查时,em>lookup 对象</em> 是用于创建方法句柄的工厂。

适用于