MethodHandles.Lookup 类
定义
重要
一些信息与预发行产品相关,相应产品在发行之前可能会进行重大修改。 对于此处提供的信息,Microsoft 不作任何明示或暗示的担保。
<当创建需要访问检查时,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
- 继承
- 属性
注解
<当创建需要访问检查时,em>lookup 对象</em> 是用于创建方法句柄的工厂。 方法句柄在调用访问时不执行访问检查,而是在创建访问时执行。 因此,创建方法句柄时必须强制实施方法句柄访问限制。 强制实施这些限制的调用方类称为 #lookupClass 查找类。
需要创建方法句柄的查找类将调用 #lookup MethodHandles.lookup
它来为自己创建工厂。 Lookup
创建工厂对象时,将确定查找类的标识,并安全地存储在对象中Lookup
。 然后,查找类(或其委托)可以使用对象上的 Lookup
工厂方法为访问检查的成员创建方法句柄。 这包括允许查找类的所有方法、构造函数和字段,甚至私有方法。
<h1>“lookups”>Lookup Factory Methods</h1> 对象上的 Lookup
工厂方法对应于方法、构造函数和字段的所有主要用例。 工厂方法创建的每个方法句柄都是特定 <em>字节码行为</em> 的功能等效项。 (Java 虚拟机规范的第 5.4.3.5 节介绍了字节码行为。下面是这些工厂方法与结果方法处理的行为之间的对应摘要:<表边框=1 cellpadding=5 summary=“lookup method behaviors”tr><th>“<>equiv”>lookup expression</<>>th th member</th th bytecode behavior</><>th></tr><tr><td/td><java.lang.invoke.MethodHandles.Lookup#findGetter lookup.findGetter(C.class,"f",FT.class)
td<>td/td td>(T) this.f;
><<><FT f;
/tr><><tr><td><java.lang.invoke.MethodHandles.Lookup#findStaticGetter lookup.findStaticGetter(C.class,"f",FT.class)
/td><td><static
br><FT f;
/td><td></tr<><>td<<>(T) C.f;
>java.lang.invoke.MethodHandles.Lookup#findSetter lookup.findSetter(C.class,"f",FT.class)
/td<>td/td td><FT f;
/td<>>< td<this.f = x;
>/tr<<>>tdjava.lang.invoke.MethodHandles.Lookup#findStaticSetter lookup.findStaticSetter(C.class,"f",FT.class)
></td td/td><static
><<FT f;
> td br/><td td<><>C.f = arg;
/tr tr><><td>java.lang.invoke.MethodHandles.Lookup#findVirtual lookup.findVirtual(C.class,"m",MT)
</td><td>T m(A*);
</td><td/td></tr><<>tdjava.lang.invoke.MethodHandles.Lookup#findStatic lookup.findStatic(C.class,"m",MT)
>(T) this.m(arg*);
<<>/td<<>static
>td br<>T m(A*);
/td><td/td<(T) C.m(arg*);
>/tr>><<td>java.lang.invoke.MethodHandles.Lookup#findSpecial lookup.findSpecial(C.class,"m",MT,this.class)
</td>< td/td><td/td td/><td tdT m(A*);
<>>(T) super.m(arg*);
</<>tr tr><><td><java.lang.invoke.MethodHandles.Lookup#findConstructor lookup.findConstructor(C.class,MT)
/td td><<>C(A*);
/td><td>new C(arg*);
</><<>tr<> td/td td/td<>td><>java.lang.invoke.MethodHandles.Lookup#unreflectGetter lookup.unreflectGetter(aField)
(static
)?<br><FT f;
/td td></td>><(FT) aField.get(thisOrNull);
</tr>><<td/td<>java.lang.invoke.MethodHandles.Lookup#unreflectSetter lookup.unreflectSetter(aField)
>< td>(static
)?<br><FT f;
/td td></td>><aField.set(thisOrNull, arg);
</tr>><<td/td<>java.lang.invoke.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)
>< td>(static
)?<br><T m(A*);
/td td></td>(T) aMethod.invoke(thisOrNull, arg*);
<<>/tr><><td>java.lang.invoke.MethodHandles.Lookup#unreflectConstructor lookup.unreflectConstructor(aConstructor)
</td<>td<C(A*);
>/td<><> td<(C) aConstructor.newInstance(arg*);
>/><><tr tr td/td td/td<>java.lang.invoke.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)
>< td>(static
)?<br>T m(A*);
</td><td/td><(T) aMethod.invoke(thisOrNull, arg*);
<>/tr></table>
在这里,该类型 C
是正在搜索成员的类或接口,该成员记录为查找方法中命名 refc
的参数。 方法类型 MT
由返回类型和 T
参数类型的 A*
序列组成。 构造函数还具有一系列参数类型 A*
,并被视为返回类型 C
的新创建的对象。 这两MT
种类型以及字段类型FT
都记录为名为 <this
代表类型的 C
自我引用;如果存在,则始终是方法句柄调用的前导参数。 (对于某些 protected
成员, this
可能限制为查找类的类型;请参阅下文。该名称 arg
代表所有其他方法句柄参数。 在核心反射 API 的代码示例中,如果访问的方法或字段是静态的,则名称 thisOrNull
表示 null 引用, this
否则为 null 引用。 名称和aMethod
aField
aConstructor
代表对应于给定成员的反射对象。
如果给定成员是变量 arity(即方法或构造函数),则返回的方法句柄也将是 MethodHandle#asVarargsCollector 变量 arity。 在所有其他情况下,返回的方法句柄将为固定的 arity。 <p style=“font-size:smaller;”><em>Discussion:</em> looked-up 方法句柄与基础类成员和字节码行为之间的等价性可以分为几种方法: <ul style=“font-size:smaller;”><li>如果 C
无法从查找类的加载程序进行符号访问,则即使没有等效的 Java 表达式或字节编码常量,查找仍可以成功。 <同样>,如果T
MT
或无法从查找类的加载程序进行符号访问,则查找仍可以成功。 例如,无论请求的类型如何,查找 MethodHandle.invokeExact
并 MethodHandle.invoke
始终成功。 <li>如果安装了安全管理器,则可以禁止查找各种理由(请参阅下文)。 相比之下, ldc
常量上的 CONSTANT_MethodHandle
指令不受安全管理器检查的约束。 <li>如果查找方法的 arity 非常大,则方法句柄创建可能会失败,因为方法句柄类型具有太多参数。 </ul>
<创建方法句柄时,h1>“access”>访问检查</h1> 访问检查在工厂方法 Lookup
中应用。 这是与核心反射 API 的关键区别,因为 java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke
每次调用都会针对每个调用方执行访问检查。
所有访问检查都从对象 Lookup
开始,该对象将记录的查找类与创建方法句柄的所有请求进行比较。 单个 Lookup
对象可用于创建任意数量的访问检查方法句柄,所有句柄都针对单个查找类进行检查。
Lookup
对象可以与其他受信任的代码(例如元对象协议)共享。 共享 Lookup
对象委托对查找类的私有成员创建方法句柄的功能。 即使特权代码使用 Lookup
对象,访问检查也仅限于原始查找类的特权。
查找可能会失败,因为查阅类无法访问包含类,或者缺少所需的类成员,或者由于所需的类成员无法访问查阅类,或者由于查阅对象不够受信任而无法访问该成员。 在上述任一情况下,将从尝试的查找中引发 a 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 节。此外,如果所需成员是其他包中的非静态字段或方法,则生成的方法句柄只能应用于查阅类的对象或其子类之一。 通过将前导 this
参数的类型从 C
(这必然是查阅类的超级类)缩小到查找类本身,来强制实施此要求。
JVM 对 invokespecial
指令施加类似的要求,即接收方参数必须与解析的方法 <em>和</em> 当前类相匹配。 同样,通过将前导参数的类型缩小到生成的方法句柄来强制实施此要求。 (请参阅 Java 虚拟机规范,第 4.10.1.9 节。
JVM 将构造函数和静态初始值设定项块表示为具有特殊名称("<init>"
和 "<clinit>"
)的内部方法。 调用指令的内部语法允许它们引用此类内部方法,就像它们是普通方法一样,但 JVM 字节码验证程序拒绝它们。 查找此类内部方法将生成一个 NoSuchMethodException
。
在某些情况下,嵌套类之间的访问是通过创建包装方法来访问同一顶级声明中另一个类的私有方法来获取的。 例如,嵌套类 C.D
可以访问其他相关类(例如 C
, C.D.E
或 C.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>access private fields, methods, and constructors of the lookup class <li>create method handles which invokeer sensitive methods, such Class.forName
<li create method handles Lookup#findSpecial emulate invokespecial
which instructions <li>>avoid package access checks for classes access for <class li Lookup#in delegated lookup objects
>create, which have private access to other classes within the same package member </ul><p style=“font-size:smaller;”>其中每个权限都是一个事实,即具有专用访问权限的查找对象可以安全地追溯到原始类,其字节代码行为和 Java 语言访问权限可以通过方法句柄可靠地确定和模拟。
<h1>“secmgr”>安全管理器交互</h1> 尽管字节码指令只能引用相关类加载程序中的类,但只要引用其 Class
对象可用,此 API 就可以在任何类中搜索方法。 核心反射 API 也有可能使用此类跨加载程序引用,并且无法字节编码指令,例如 invokestatic
或 getfield
。 有一个 java.lang.SecurityManager 安全管理器 API,允许应用程序检查此类跨加载程序引用。 这些检查适用于 MethodHandles.Lookup
API 和核心反射 API(如上找到)。java.lang.Class Class
如果存在安全管理器,则成员查找将受到其他检查。 从 1 到 3 次调用安全管理器。 这些调用中的任何一个都可以通过抛出一个 java.lang.SecurityException SecurityException
来拒绝访问。 定义为 smgr
安全管理器, lookc
作为当前查找对象的查找类, refc
作为要在其中查找成员的包含类,以及 defc
作为实际定义成员的类。 如果当前查找对象没有专用访问权限,则该值 lookc
定义为 <em>不存在</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
不存在,如果refc
defc
不存在,则调用它SecurityManager#checkPackageAccess smgr.checkPackageAccess(defcPkg)
,其中是defcPkg
包defc
。 </ul> 安全检查在其他访问检查通过后执行。 因此,上述规则预先提供公共成员,或者从有权访问成员的查阅类访问该成员。
<h1>“callsens<”>Caller 敏感方法/h1> 少数 Java 方法具有称为调用方敏感度的特殊属性。 <em>调用方敏感</em> 方法的行为可能有所不同,具体取决于其即时调用方的身份。
如果请求调用方敏感方法的方法句柄,则字节代码行为的常规规则适用,但它们以特殊方式考虑查找类。 生成的方法句柄的行为就像是从查找类中包含的指令调用的,以便调用方敏感方法检测查找类。 (相比之下,忽略方法句柄的调用方。因此,对于调用方敏感的方法,不同的查找类可能会导致不同的行为方法句柄。
如果查找对象是 #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.Lookup
Java 文档
本页的某些部分是根据 Android 开放源代码项目创建和共享的工作进行的修改,并根据 Creative Commons 2.5 属性许可证中所述的术语使用。
字段
Package |
已过时.
表示访问(默认访问)的单位掩码 |
Private |
已过时.
表示访问的单位掩码 |
Protected |
已过时.
表示访问的单位掩码 |
Public |
已过时.
表示访问的单位掩码 |
属性
Class |
返回此 |
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,以访问类型类中声明的类型 |
FindVarHandle(Class, String, Class) |
生成一个 VarHandle,它授予对类型类 |
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,它授予对类型类 |
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> 是用于创建方法句柄的工厂。 |