促进创建简单“函数对象”的方法,这些函数对象通过委托给提供的 MethodHandle 来实现一个或多个接口,可能在类型适配和参数的部分评估之后。这些方法通常用作 invokedynamic 调用站点的 bootstrap methods,以支持 Java 编程语言的 lambda expression 和 method reference expression 功能。
间接访问所提供的 MethodHandle 指定的行为通过三个阶段按顺序进行:
Linkage 在调用此类中的方法时发生。它们将要实现的接口(通常是 functional interface ,具有单个抽象方法的接口)、要实现的该接口的方法的名称和签名、描述该方法所需实现行为的 直接方法句柄 以及可能的其他参数作为参数附加元数据,并生成一个
CallSite,其目标可用于创建合适的函数对象。链接可能涉及动态加载实现目标接口的新类,或重新使用合适的现有类。
CallSite可以被视为函数对象的“工厂”,因此这些链接方法被称为“元工厂”。Capture 在调用
CallSite的目标时发生,通常是通过invokedynamic调用站点,生成一个函数对象。对于单个工厂CallSite,这可能会发生多次。如果行为
MethodHandle具有超出指定接口方法的其他参数,则这些参数称为 captured parameters ,必须作为参数提供给CallSite目标。捕获参数的预期数量和类型在链接期间确定。捕获可能涉及新函数对象的分配,或者可能返回合适的现有函数对象。捕获产生的函数对象的身份是不可预测的,因此对身份敏感的操作(例如引用相等性、对象锁定和
System.identityHashCode())可能会在不同的实现中产生不同的结果,甚至在同一实现中的不同调用中也会产生不同的结果。Invocation 在函数对象上调用已实现的接口方法时发生。对于单个函数对象,这可能会发生多次。调用实现
MethodHandle引用的方法,将捕获的参数和调用参数传递给它。返回该方法的结果。
限制调用时允许的输入或结果集有时很有用。例如,当通用接口 Predicate<T> 被参数化为 Predicate<String> 时,输入必须是 String ,即使要实现的方法允许任何 Object 。在链接时,一个额外的MethodType 参数描述了“动态”方法类型;在调用时,参数和最终结果将根据这个 MethodType 检查。
此类提供两种形式的链接方法:使用优化协议的标准版本 (metafactory(MethodHandles.Lookup, String, MethodType, MethodType, MethodHandle, MethodType) ) 和替代版本 altMetafactory(MethodHandles.Lookup, String, MethodType, Object...) )。备用版本是标准版本的概括,通过标志和附加参数对生成的函数对象的行为提供额外的控制。替代版本增加了管理函数对象的以下属性的能力:
- Multiple methods. 有时实现方法签名的多个变体很有用,涉及参数或返回类型适配。当一种方法的多个不同 VM 签名在逻辑上被语言认为是相同的方法时,就会发生这种情况。标志
FLAG_BRIDGES表示将提供额外的MethodType的列表,每个都将由生成的函数对象实现。这些方法将共享相同的名称和实例化类型。 - Multiple interfaces. 如果需要,函数对象可以实现多个接口。 (这些附加接口通常是没有方法的标记接口。)标志
FLAG_MARKERS表示将提供附加接口列表,每个接口都应由生成的函数对象实现。 - Serializability.生成的函数对象一般不支持序列化。如果需要,
FLAG_SERIALIZABLE可用于指示函数对象应该是可序列化的。可序列化函数对象将使用类SerializedLambda的实例作为它们的序列化形式,这需要捕获类(MethodHandles.Lookup参数caller描述的类)的额外帮助;有关详细信息,请参阅SerializedLambda。
假设链接参数如下:
factoryType(描述CallSite签名)有K个参数类型(D1..Dk)和返回类型Rd;interfaceMethodType(描述实现的方法类型)有N个参数,类型为(U1..Un),返回类型为Ru;implementation(MethodHandle提供实现)有 M 个参数,类型为 (A1..Am) 和返回类型 Ra(如果方法描述实例方法,则此方法句柄的方法类型已经包含一个额外的第一个参数,对应于接收者);dynamicMethodType(允许限制调用)有 N 个参数,类型为 (T1..Tn),返回类型为 Rt。
那么下面的链接不变量必须成立:
interfaceMethodType和dynamicMethodType具有相同的元数 N,并且对于 i=1..N,Ti 和 Ui 是同一类型,或者 Ti 和 Ui 都是引用类型并且 Ti 是 Ui 的子类型- Rt 和 Ru 是同一类型,或者都是引用类型且 Rt 是 Ru 的子类型
- K + N = M
- 对于 i=1..K,Di = Ai
- 对于i=1..N,Ti适配Aj,其中j=i+k
- 返回类型 Rt 为 void,或者返回类型 Ra 不为 void 且适配 Rt
此外,在捕获时,如果 implementation 对应于一个实例方法,并且有任何捕获参数(K > 0 ),那么第一个捕获参数(对应于接收者)必须是非空的。
类型 Q 被认为适用于 S,如下所示:
| Q | S | 链接时检查 | 调用时检查 |
|---|---|---|---|
| 原始 | 原始 | Q 可以通过原始扩展转换转换为 S | 没有任何 |
| 原始 | Reference | S 是 Wrapper(Q) 的超类型 | 从 Wrapper(Q) 投射到 S |
| Reference | 原始 | 对于参数类型:Q 是原始包装器,Primitive(Q) 可以扩展为 S 对于返回类型:如果 Q 是原始包装器,请检查 Primitive(Q) 是否可以扩展为 S |
如果 Q 不是原始包装器,则将 Q 转换为基础 Wrapper(S);例如数字类型的数字 |
| Reference | Reference | 对于参数类型:S 是 Q 的超类型 对于返回类型:无 |
从Q投到S |
- API 注意:
-
这些链接方法旨在支持 Java 语言中 lambda expressions 和 method references 的计算。对于源代码中的每个 lambda 表达式或方法引用,都有一个目标类型,它是一个功能接口。评估 lambda 表达式会生成其目标类型的对象。评估 lambda 表达式的推荐机制是将 lambda 主体脱糖为方法,调用 invokedynamic 调用站点,其静态参数列表描述功能接口的唯一方法和脱糖实现方法,并返回一个对象(lambda 对象)实现目标类型。 (对于方法引用,实现方法只是被引用的方法;不需要脱糖。)
实现方法的参数列表和接口方法的参数列表可能在几个方面有所不同。实现方法可能有额外的参数来容纳 lambda 表达式捕获的参数;允许的参数调整也可能导致差异,例如转换、装箱、拆箱和原始加宽。 (Varargs 适配不由元工厂处理;这些应由调用者处理。)
Invokedynamic 调用站点有两个参数列表:静态参数列表和动态参数列表。静态参数列表存放在常量池中;动态参数在捕获时被压入操作数栈。引导方法可以访问整个静态参数列表(在本例中,包括描述实现方法、目标接口和目标接口方法的信息),以及描述数字和静态类型的方法签名(但不是值)动态参数和 invokedynamic 站点的静态返回类型。
实现方法用引用方法或构造方法的直接方法句柄来描述。理论上,可以使用任何方法句柄,但这与某些实现技术不兼容,并且会使实现必须完成的工作复杂化。
- 自从:
- 1.8
-
字段摘要
字段修饰符和类型Field描述static final int指示 lambda 对象的备用元工厂标志需要调用implementation的其他方法static final intaltMetafactory(java.lang.invoke.MethodHandles.Lookup, java.lang.String, java.lang.invoke.MethodType, java.lang.Object...)的标志表示 lambda 对象实现了除Serializable之外的其他接口static final int -
方法总结
修饰符和类型方法描述static CallSitealtMetafactory(MethodHandles.Lookup caller, String interfaceMethodName, MethodType factoryType, Object... args) 在适当的类型调整和参数的部分评估之后,通过委托给提供的MethodHandle来促进实现一个或多个接口的简单“函数对象”的创建。static CallSitemetafactory(MethodHandles.Lookup caller, String interfaceMethodName, MethodType factoryType, MethodType interfaceMethodType, MethodHandle implementation, MethodType dynamicMethodType) 在适当的类型调整和参数的部分评估之后,通过委托给提供的MethodHandle来促进实现一个或多个接口的简单“函数对象”的创建。
-
字段详细信息
-
FLAG_SERIALIZABLE
public static final int FLAG_SERIALIZABLEaltMetafactory(java.lang.invoke.MethodHandles.Lookup, java.lang.String, java.lang.invoke.MethodType, java.lang.Object...)的标志指示 lambda 对象必须是可序列化的- 参见:
-
FLAG_MARKERS
public static final int FLAG_MARKERSaltMetafactory(java.lang.invoke.MethodHandles.Lookup, java.lang.String, java.lang.invoke.MethodType, java.lang.Object...)的标志表示 lambda 对象实现了除Serializable之外的其他接口- 参见:
-
FLAG_BRIDGES
public static final int FLAG_BRIDGES指示 lambda 对象的备用元工厂标志需要调用implementation的其他方法- 参见:
-
-
方法详情
-
metafactory
public static CallSite metafactory(MethodHandles.Lookup caller, String interfaceMethodName, MethodType factoryType, MethodType interfaceMethodType, MethodHandle implementation, MethodType dynamicMethodType) throws LambdaConversionException 在适当的类型调整和参数的部分评估之后,通过委托给提供的MethodHandle来促进实现一个或多个接口的简单“函数对象”的创建。通常用作invokedynamic调用站点的 bootstrap method,以支持 Java 编程语言的 lambda expression 和 method reference expression 功能。这是标准的流线型元工厂;
altMetafactory(MethodHandles.Lookup, String, MethodType, Object...)提供了额外的灵活性。above提供了此方法行为的一般描述。当调用此方法返回的
CallSite的目标时,生成的函数对象是一个类的实例,该类实现由factoryType的返回类型命名的接口,声明一个名称由interfaceMethodName给出且签名由interfaceMethodType给出的方法。它还可以覆盖Object中的其他方法。- 参数:
caller- 表示具有调用方可访问权限的查找上下文。具体来说,查找上下文必须有 完全权限访问 。当与invokedynamic一起使用时,它由 VM 自动堆叠。interfaceMethodName- 要实现的方法的名称。当与invokedynamic一起使用时,它由InvokeDynamic结构的NameAndType提供,并由 VM 自动堆叠。factoryType-CallSite的预期签名。参数类型表示捕获变量的类型;返回类型是要实现的接口。当与invokedynamic一起使用时,它由InvokeDynamic结构的NameAndType提供,并由 VM 自动堆叠。interfaceMethodType- 函数对象要实现的方法的签名和返回类型。implementation- 一个直接方法句柄,描述在调用时应调用的实现方法(适当调整参数类型和返回类型,并将捕获的参数添加到调用参数之前)。dynamicMethodType- 应在调用时动态强制执行的签名和返回类型。在简单的用例中,这与interfaceMethodType相同。- 返回:
-
一个 CallSite,其目标可用于执行捕获,生成由
factoryType命名的接口的实例 - 抛出:
LambdaConversionException- 如果caller没有完全权限访问,或者如果interfaceMethodName不是有效的 JVM 方法名称,或者如果factoryType的返回类型不是接口,或者如果implementation不是引用方法或构造函数的直接方法句柄,或者如果违反了链接不变量,如above所定义。NullPointerException- 如果任何参数是null。SecurityException- 如果存在安全管理器,它会从caller拒绝访问 到implementation的包。
-
altMetafactory
public static CallSite altMetafactory(MethodHandles.Lookup caller, String interfaceMethodName, MethodType factoryType, Object ... args) throws LambdaConversionException 在适当的类型调整和参数的部分评估之后,通过委托给提供的MethodHandle来促进实现一个或多个接口的简单“函数对象”的创建。通常用作invokedynamic调用站点的 bootstrap method,以支持 Java 编程语言的 lambda expression 和 method reference expression 功能。这是通用的、更灵活的元工厂;
metafactory(java.lang.invoke.MethodHandles.Lookup, String, MethodType, MethodType, MethodHandle, MethodType)提供了精简版。above提供了此方法行为的一般描述。此方法的参数列表包括三个固定参数,对应于 VM 在
invokedynamic调用中为引导方法自动堆叠的参数,以及一个包含其他参数的Object[]参数。此方法声明的参数列表是:CallSite altMetafactory(MethodHandles.Lookup caller, String interfaceMethodName, MethodType factoryType, Object... args)但它的行为就像参数列表如下所示:
CallSite altMetafactory(MethodHandles.Lookup caller, String interfaceMethodName, MethodType factoryType, MethodType interfaceMethodType, MethodHandle implementation, MethodType dynamicMethodType, int flags, int altInterfaceCount, // IF flags has MARKERS set Class... altInterfaces, // IF flags has MARKERS set int altMethodCount, // IF flags has BRIDGES set MethodType... altMethods // IF flags has BRIDGES set )metafactory(MethodHandles.Lookup, String, MethodType, MethodType, MethodHandle, MethodType)的参数列表中出现的参数与该方法中的参数具有相同的规范。附加参数解释如下:flags表示附加选项;这是所需标志的按位或。定义的标志是FLAG_BRIDGES、FLAG_MARKERS和FLAG_SERIALIZABLE。altInterfaceCount是函数对象应实现的附加接口的数量,当且仅当设置了FLAG_MARKERS标志时才存在。altInterfaces是要实现的附加接口的可变长度列表,其长度等于altInterfaceCount,并且当且仅当设置了FLAG_MARKERS标志时才存在。altMethodCount是函数对象应实现的附加方法签名的数量,当且仅当设置了FLAG_BRIDGES标志时才存在。altMethods是要实现的附加方法签名的可变长度列表,其长度等于altMethodCount,并且当且仅当设置了FLAG_BRIDGES标志时才存在。
altInterfaces命名的每个类都受到与Rd相同的限制,factoryType的返回类型,如above所述。altMethods命名的每个MethodType都受到与interfaceMethodType相同的限制,如above所述。当
flags中设置了 FLAG_SERIALIZABLE 时,函数对象将实现Serializable,并且将有一个返回适当的SerializedLambda的writeReplace方法。caller类必须具有适当的$deserializeLambda$方法,如SerializedLambda中所述。当调用从此方法返回的
CallSite的目标时,生成的函数对象是具有以下属性的类的实例:- 该类实现由
factoryType的返回类型命名的接口以及由altInterfaces命名的任何接口 - 该类声明方法的名称由
interfaceMethodName给出,签名由interfaceMethodType给出,附加签名由altMethods给出 - 该类可以覆盖
Object中的方法,并可以实现与序列化相关的方法。
- 参数:
caller- 表示具有调用方可访问权限的查找上下文。具体来说,查找上下文必须有 完全权限访问 。当与invokedynamic一起使用时,它由 VM 自动堆叠。interfaceMethodName- 要实现的方法的名称。当与invokedynamic一起使用时,它由InvokeDynamic结构的NameAndType提供,并由 VM 自动堆叠。factoryType-CallSite的预期签名。参数类型表示捕获变量的类型;返回类型是要实现的接口。当与invokedynamic一起使用时,它由InvokeDynamic结构的NameAndType提供,并由 VM 自动堆叠。args-Object数组,包含所需参数interfaceMethodType、implementation、dynamicMethodType、flags和任何可选参数,如上所述- 返回:
-
一个 CallSite,其目标可用于执行捕获,生成由
factoryType命名的接口的实例 - 抛出:
LambdaConversionException- 如果caller没有完全权限访问,或者如果interfaceMethodName不是有效的 JVM 方法名称,或者如果factoryType的返回类型不是接口,或者如果altInterfaces中的任何一个不是接口,或者如果implementation不是一个引用方法或构造函数的直接方法句柄,或者是否违反了链接不变量,如定义的above。NullPointerException- 如果任何参数或args的任何组件是null。IllegalArgumentException- 如果args的组件的数量或类型不遵循上述规则,或者如果altInterfaceCount或altMethodCount是负整数。SecurityException- 如果存在安全管理器,它会从caller拒绝访问 到implementation的包。
-