接口 | 描述 |
---|---|
MethodHandleInfo |
通过将直接方法句柄破解成其宪法符号部分获得的象征性参考。
|
类 | 描述 |
---|---|
CallSite |
A CallSite 是变量MethodHandle 的持有人,它被称为它的target 。
|
ConstantCallSite |
A ConstantCallSite 是一个CallSite ,其目标是永久性的,永远不能更改。
|
LambdaMetafactory |
有助于创建简单的“功能对象”的方法,通过委派给提供的 MethodHandle 实现一个或多个接口 ,可能在类型适配和参数的部分评估之后。
|
MethodHandle |
方法句柄是一个类型化的,直接可执行的对底层方法,构造函数,字段或类似低级操作的引用,具有参数或返回值的可选转换。
|
MethodHandleProxies |
此类仅由静态方法组成,可帮助将方法句柄修改为其他JVM类型(如接口)。
|
MethodHandles |
该类仅由静态方法组成,或者返回方法句柄。
|
MethodHandles.Lookup |
查找对象是创建方法句柄的工厂,当创建需要访问检查时。
|
MethodType |
方法类型表示方法句柄接受和返回的参数和返回类型,或方法句柄调用者传递和预期的参数和返回类型。
|
MutableCallSite |
A MutableCallSite 是一个CallSite ,其目标变量的行为像普通字段。
|
SerializedLambda |
lambda表达式的序列化形式。
|
SwitchPoint |
A
SwitchPoint 是可以向其他线程发布状态转换的对象。
|
VolatileCallSite |
A VolatileCallSite 是一个CallSite ,其目标像一个volatile变量。
|
异常 | 描述 |
---|---|
LambdaConversionException |
LambdaConversionException
|
WrongMethodTypeException |
抛出以表示代码尝试通过错误的方法类型调用方法句柄。
|
java.lang.invoke
包包含由Java核心类库和虚拟机直接提供的动态语言支持。
如Java虚拟机规范中所述,此包中的某些类型与虚拟机中的动态语言支持具有特殊关系:
MethodHandle
类包含signature polymorphic methods ,无论其类型描述符如何 ,都可以链接。 通常,方法链接需要类型描述符的精确匹配。 MethodHandle
和MethodType
的即时常量 。 invokedynamic
发生都称为动态呼叫站点 。
invokedynamic
说明 在JVM可以执行动态呼叫站点( invokedynamic
指令)之前,呼叫站点必须首先被链接 。 链接是通过调用引导方法来实现的,该方法被赋予呼叫站点的静态信息内容,并且必须产生给出呼叫站点行为的method handle
。
每个invokedynamic
指令静态地将自己的引导方法指定为常量池引用。 常量池引用还指定调用站点的名称和类型描述符,就像invokevirtual
和其他调用指令一样。
链接开始于解决引导方法的常量池条目,并解析动态调用站点的类型描述符的MethodType
对象。 该解析过程可能会触发类加载。 如果类无法加载,它可能会抛出错误。 该错误成为动态呼叫站点执行的异常终止。 Linkage不会触发类初始化。
至少三个值调用引导方法:
MethodHandles.Lookup
,一个在动态调用站点发生的调用者类中的查找对象 String
,呼叫站点中String
的方法名称 MethodType
,解析的类型描述符的调用 MethodHandle.invoke
一样 。
返回的结果必须是CallSite
(或子类)。
调用站点的目标类型必须与从动态调用站点的类型描述符派生的类型完全相同,并传递给引导方法。
然后呼叫站点将永久链接到动态呼叫站点。
如JVM规范记录,从动态调用网站的链接而产生的所有故障是由报道BootstrapMethodError
,这是抛出动态调用点执行的异常终止。 如果发生这种情况,将会对所有后续尝试执行动态调用站点抛出相同的错误。
如果有多个这样的线程,引导方法可能会同时在多个线程中调用。 因此,访问全局应用程序数据的引导方法必须采取针对竞争条件的通常预防措施。 无论如何,每个invokedynamic
指令都将被取消链接或链接到唯一的CallSite
对象。
在需要具有单独可变行为的动态调用站点的应用程序中,它们的引导方法应该产生不同的CallSite
对象,每个连接请求一个。 或者,应用程序可以将单个CallSite
对象链接到多个invokedynamic
指令,在这种情况下,每个指令将变为目标方法。
如果多个线程同时为单个动态调用站点执行引导方法,则JVM必须选择一个CallSite
对象并将其明显地安装到所有线程。 允许任何其他引导方法调用完成,但其结果将被忽略,并且其动态调用站点调用继续处理原始选择的目标对象。
讨论:这些规则不能使JVM重复动态调用站点,也不会发出“无效”引导方法调用。 每个动态调用站点在其第一次调用之前,最多只能从一个链接转换为一个链接。 没有办法撤销完成的引导方法调用的效果。
MethodHandle.invoke
,其详细的类型是任意的。
例如,第一个参数可以是Object
而不是MethodHandles.Lookup
,返回类型也可以是Object
而不是CallSite
。
(请注意,堆栈参数的类型和数量限制了引导方法的合法类型,以适当类型的静态方法和CallSite子类的CallSite
函数。)
如果给定的invokedynamic
指令没有指定静态参数,则将在三个参数上调用指令的引导方法,传达指令的调用者类,名称和方法类型。 如果invokedynamic
指令指定一个或多个静态参数,那些值将作为附加参数传递给方法句柄。 (请注意,因为任何方法都有255个参数的限制,因此可以提供最多251个额外的参数,因为引导方法处理本身,并且前三个参数也必须被堆叠。)引导方法将被调用,就像MethodHandle.invoke
或invokeWithArguments
。 (没有办法说出差异。)
对于普通参数转换规则MethodHandle.invoke
适用于所有堆叠的论点。 例如,如果推送的值是原始类型,则可以通过拳击转换将其转换为引用。 如果引导方法是一个可变的arity方法(它的修饰符位设置为0x0080
),那么这里指定的一些或全部参数可以被收集到一个尾随的数组参数中。 (这不是一个特殊的规则,而是CONSTANT_MethodHandle常量之间的CONSTANT_MethodHandle
的有用结果,变量arity方法的修饰符位和asVarargsCollector
转换。)
给出这些规则,这里是法律引导方法声明的示例,给出了各种数字N
的额外参数。 第一行(标记为*
)将适用于任何数量的额外参数。
CallSite bootstrap(Lookup caller, String name, MethodType type, Object... args)
* CallSite bootstrap(Object... args)
* CallSite bootstrap(Object caller, Object... nameAndTypeWithArgs)
0 CallSite bootstrap(Lookup caller, String name, MethodType type)
0 CallSite bootstrap(Lookup caller, Object... nameAndType)
1 CallSite bootstrap(Lookup caller, String name, MethodType type, Object arg)
2 CallSite bootstrap(Lookup caller, String name, MethodType type, Object... args)
2 CallSite bootstrap(Lookup caller, String name, MethodType type, String... args)
2 CallSite bootstrap(Lookup caller, String name, MethodType type, String x, int y)
CONSTANT_String
和CONSTANT_Integer
,分别。
第二个到最后一个例子假设所有额外的参数都是类型CONSTANT_String
。
其他示例适用于所有类型的额外参数。
如上所述,引导方法的实际方法类型可以变化。 例如,第四个参数可以是MethodHandle
,如果是CONSTANT_InvokeDynamic
条目中对应的常量的类型。 在这种情况下, MethodHandle.invoke
呼叫将通过额外的方法作为处理常数Object
,但类型匹配机械MethodHandle.invoke
将施放返回参考MethodHandle
调用的自举方法之前。 (如果传递一个字符串常量,那么生成的代码不太合适,那么该转换将失败,导致一个BootstrapMethodError
))
请注意,作为上述规则的结果,引导方法可以接受原始参数,如果它可以由常量池条目表示。 然而,类型的参数boolean
, byte
, short
,或char
不能自举方法来创建的,因为这样的常量不能直接在常量池中表示,并且自举方法的调用将不执行必要的基本收缩转换。
额外的引导方法参数旨在允许语言实现者安全和紧凑地编码元数据。 原则上,名称和额外的参数是冗余的,因为每个调用站点都可以被赋予自己独特的引导方法。 这种做法很可能会产生大型的类文件和常量池。