模块 java.base

类 LambdaMetafactory

java.lang.Object
java.lang.invoke.LambdaMetafactory

public final class LambdaMetafactory extends Object

促进创建简单“函数对象”的方法,这些函数对象通过委托给提供的 MethodHandle 来实现一个或多个接口,可能在类型适配和参数的部分评估之后。这些方法通常用作 invokedynamic 调用站点的 bootstrap methods,以支持 Java 编程语言的 lambda expressionmethod 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;
  • implementationMethodHandle 提供实现)有 M 个参数,类型为 (A1..Am) 和返回类型 Ra(如果方法描述实例方法,则此方法句柄的方法类型已经包含一个额外的第一个参数,对应于接收者);
  • dynamicMethodType(允许限制调用)有 N 个参数,类型为 (T1..Tn),返回类型为 Rt。

那么下面的链接不变量必须成立:

  • interfaceMethodTypedynamicMethodType 具有相同的元数 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 expressionsmethod references 的计算。对于源代码中的每个 lambda 表达式或方法引用,都有一个目标类型,它是一个功能接口。评估 lambda 表达式会生成其目标类型的对象。评估 lambda 表达式的推荐机制是将 lambda 主体脱糖为方法,调用 invokedynamic 调用站点,其静态参数列表描述功能接口的唯一方法和脱糖实现方法,并返回一个对象(lambda 对象)实现目标类型。 (对于方法引用,实现方法只是被引用的方法;不需要脱糖。)

实现方法的参数列表和接口方法的参数列表可能在几个方面有所不同。实现方法可能有额外的参数来容纳 lambda 表达式捕获的参数;允许的参数调整也可能导致差异,例如转换、装箱、拆箱和原始加宽。 (Varargs 适配不由元工厂处理;这些应由调用者处理。)

Invokedynamic 调用站点有两个参数列表:静态参数列表和动态参数列表。静态参数列表存放在常量池中;动态参数在捕获时被压入操作数栈。引导方法可以访问整个静态参数列表(在本例中,包括描述实现方法、目标接口和目标接口方法的信息),以及描述数字和静态类型的方法签名(但不是值)动态参数和 invokedynamic 站点的静态返回类型。

实现方法用引用方法或构造方法的直接方法句柄来描述。理论上,可以使用任何方法句柄,但这与某些实现技术不兼容,并且会使实现必须完成的工作复杂化。

自从:
1.8
  • 字段详细信息

  • 方法详情

    • 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 expressionmethod 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 expressionmethod 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 数组,包含所需参数 interfaceMethodTypeimplementationdynamicMethodTypeflags 和任何可选参数,如上所述
      返回:
      一个 CallSite,其目标可用于执行捕获,生成由 factoryType 命名的接口的实例
      抛出:
      LambdaConversionException - 如果 caller 没有完全权限访问,或者如果 interfaceMethodName 不是有效的 JVM 方法名称,或者如果 factoryType 的返回类型不是接口,或者如果 altInterfaces 中的任何一个不是接口,或者如果 implementation 不是一个引用方法或构造函数的直接方法句柄,或者是否违反了链接不变量,如定义的above
      NullPointerException - 如果任何参数或 args 的任何组件是 null
      IllegalArgumentException - 如果 args 的组件的数量或类型不遵循上述规则,或者如果 altInterfaceCountaltMethodCount 是负整数。
      SecurityException - 如果存在安全管理器,它会从 caller 拒绝访问implementation 的包。