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