模块  java.base
软件包  java.lang.invoke

Class LambdaMetafactory


  • public final class LambdaMetafactory
    extends Object

    通过委托给提供的MethodHandle ,可能在对参数进行类型调整和部分评估之后,便于创建实现一个或多个接口的简单“功能对象”的方法。 这些方法通常用作invokedynamic调用站点的引导方法 ,以支持Java编程语言的lambda表达式方法引用表达式功能。

    对提供的MethodHandle指定的行为的间接访问按顺序进行,分三个阶段:

    • 调用此类中的方法时发生链接 它们将要实现的接口作为参数(通常是功能接口 ,具有单个抽象方法的接口),要实现的接口的方法的名称和签名,描述该方法的期望实现行为的方法句柄,以及可能还有其他元数据,并生成CallSite其目标可用于创建合适的函数对象。 链接可能涉及动态加载实现目标接口的新类。 CallSite可以被认为是功能对象的“工厂”,因此这些链接方法被称为“元实例”。
    • 当调用CallSite的目标时,通常通过invokedynamic调用站点调用捕获 ,从而生成函数对象。 对于单个工厂CallSite这可能会发生多次。 捕获可以涉及分配新的功能对象,或者可以返回现有的功能对象。 行为MethodHandle可能具有超出指定接口方法的参数; 这些被称为捕获参数 ,必须作为参数提供给CallSite目标,并且可以早期绑定到行为MethodHandle 在链接期间确定捕获的参数的数量及其类型。 通过调用CallSite的目标生成的函数对象的标识是不可预测的,因此标识敏感的操作(例如引用相等,对象锁定和System.identityHashCode()可能在不同的实现中产生不同的结果,或者甚至在不同的调用中产生不同的结果实现。
    • 当实现的接口方法的功能对象调用发生调用 对于单个功能对象,这可能会发生多次。 使用捕获的参数和调用时提供的任何其他参数调用行为MethodHandle引用的方法,就像MethodHandle.invoke(Object...)一样

    有时限制调用时允许的输入或结果集是有用的。 例如,当通用接口Predicate<T>参数化为Predicate<String> ,输入必须是String ,即使要实现的方法允许任何Object 在链接时,附加MethodType参数描述“实例化”方法类型; 在调用时,参数和最终结果将根据MethodType进行检查。

    该类提供两种形式的链接方法:使用优化协议的标准版本( metafactory(MethodHandles.Lookup, String, MethodType, MethodType, MethodHandle, MethodType) )和备用版本altMetafactory(MethodHandles.Lookup, String, MethodType, Object...) 备用版本是标准版本的一般化,通过标志和附加参数提供对生成的函数对象行为的额外控制。 备用版本添加了管理功能对象的以下属性的功能:

    • 桥接。 实现方法签名的多种变体有时很有用,包括参数或返回类型适配。 当一个方法的多个不同VM签名在逻辑上被认为是该语言的相同方法时,会发生这种情况。 标志FLAG_BRIDGES表示将提供附加MethodType的列表,每个列表将由生成的函数对象实现。 这些方法将共享相同的名称和实例化类型。
    • 多个接口。 如果需要,函数对象可以实现多个接口。 (这些附加接口通常是没有方法的标记接口。)标志FLAG_MARKERS指示将提供附加接口的列表,每个接口都应由结果函数对象实现。
    • 串行化。 生成的函数对象通常不支持序列化。 如果需要,可以使用FLAG_SERIALIZABLE来指示函数对象应该是可序列化的。 可序列化的函数对象将使用类SerializedLambda实例作为其序列化形式,这需要捕获类的额外帮助( MethodHandles.Lookup参数caller描述的类); 有关详细信息,请参阅SerializedLambda

    假设链接参数如下:

    • invokedType (描述CallSite签名)有K个参数类型(D1..Dk)和返回类型Rd;
    • samMethodType (描述实现的方法类型)具有N个参数,类型(U1..Un)和返回类型Ru;
    • implMethodMethodHandle提供的实现具有M个参数,类型(A1..Am)和返回类型Ra(如果该方法描述了实例方法,则此方法句柄的方法类型已包含对应于接收器的额外第一个参数) ;
    • instantiatedMethodType (允许对调用的限制)具有N个参数,类型(T1..Tn)和返回类型Rt。

    然后必须保持以下链接不变量:

    • Rd是一个界面
    • implMethod是一个直接方法句柄
    • samMethodTypeinstantiatedMethodType具有相同的instantiatedMethodType ,并且对于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是空的,或者返回类型Ra不是空的并且适用于Rt

    此外,在捕获时,如果implMethod对应于实例方法,并且存在任何捕获参数( K > 0 ),则第一个捕获参数(对应于接收器)必须为非null。

    类型Q被认为适用于S,如下所示:

    adaptable types Q S Link-time checks Invocation-time checks Primitive Primitive Q can be converted to S via a primitive widening conversion None Primitive Reference S is a supertype of the Wrapper(Q) Cast from Wrapper(Q) to S Reference Primitive for parameter types: Q is a primitive wrapper and Primitive(Q) can be widened to S
    for return types: If Q is a primitive wrapper, check that Primitive(Q) can be widened to S If Q is not a primitive wrapper, cast Q to the base Wrapper(S); for example Number for numeric types Reference Reference for parameter types: S is a supertype of Q
    for return types: none Cast from Q to S
    API Note:
    这些链接方法旨在支持Java语言中lambda表达式方法引用的评估。 对于源代码中的每个lambda表达式或方法引用,都有一个目标类型,它是一个功能接口。 评估lambda表达式会生成其目标类型的对象。 用于评估lambda表达式的推荐机制是将lambda体转移到方法,调用invokedynamic调用站点,其静态参数列表描述功能接口的唯一方法和desugared实现方法,并返回一个对象(lambda对象)实现目标类型。 (对于方法引用,实现方法只是引用的方法;不需要desugaring。)

    实现方法的参数列表和接口方法的参数列表可以以多种方式不同。 实现方法可能有其他参数来容纳lambda表达式捕获的参数; 允许的参数调整也可能存在差异,例如投射,装箱,拆箱和原始加宽。 (Varargs调整不是由metafactories处理的;预计这些调整将由调用者处理。)

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

    Implementation Note:
    使用方法句柄描述实现方法。 理论上,可以使用任何方法句柄。 目前支持的是表示调用虚拟,接口,构造函数和静态方法的直接方法句柄。
    从以下版本开始:
    1.8
    • 字段详细信息

      • FLAG_SERIALIZABLE

        public static final int FLAG_SERIALIZABLE
        指示lambda对象的备用元实例的标志必须是可序列化的
        另请参见:
        常数字段值
      • FLAG_MARKERS

        public static final int FLAG_MARKERS
        指示lambda对象的备用元实例的标志实现除Serializable之外的其他标记接口
        另请参见:
        常数字段值
      • FLAG_BRIDGES

        public static final int FLAG_BRIDGES
        指示lambda对象的备用元实例的标志需要额外的桥接方法
        另请参见:
        常数字段值
    • 方法详细信息

      • metafactory

        public static CallSite metafactory​(MethodHandles.Lookup caller,
                                           String invokedName,
                                           MethodType invokedType,
                                           MethodType samMethodType,
                                           MethodHandle implMethod,
                                           MethodType instantiatedMethodType)
                                    throws LambdaConversionException
        在适当的类型适配和参数的部分评估之后,通过委托给提供的MethodHandle ,促进创建实现一个或多个接口的简单“功能对象”。 通常用作invokedynamic调用站点的引导方法 ,以支持Java编程语言的lambda表达式方法引用表达式功能。

        这是标准的,简化的metafactory; altMetafactory(MethodHandles.Lookup, String, MethodType, Object...)提供了额外的灵活性。 above提供了该方法的一般描述。

        当目标CallSite调用此方法返回的结果函数对象是它们实现了的返回类型命名的接口的类的实例invokedType ,声明由指定的名称的方法invokedName ,并给出签名samMethodType 它还可以覆盖Object其他方法。

        参数
        caller - 表示具有调用caller访问权限的查找上下文。 具体而言,查找上下文必须具有private access权限。 invokedynamic使用时,VM会自动堆叠。
        invokedName - 要实现的方法的名称。 当与invokedynamic使用时,这由InvokeDynamic结构的NameAndType提供,并由VM自动堆叠。
        invokedType -的的预期的签名CallSite 参数类型表示捕获变量的类型; 返回类型是要实现的接口。 当与invokedynamic使用时,这由InvokeDynamic结构的NameAndType提供,并由VM自动堆叠。 如果实现方法是实例方法并且此签名具有任何参数,则调用签名中的第一个参数必须对应于接收方。
        samMethodType - 由函数对象实现的签名和返回类型的方法。
        implMethod - 一个直接方法句柄,用于描述应该在调用时调用的实现方法(通过适当调整参数类型,返回类型以及在调用参数之前使用捕获的参数)。
        instantiatedMethodType - 应在调用时动态强制执行的签名和返回类型。 这可能与samMethodType相同,或者可能是它的特化。
        结果
        一个CallSite,其目标可用于执行捕获,生成由 invokedType命名的接口实例
        异常
        LambdaConversionException - 如果违反了描述的任何链接不变量above ,或者查找上下文不具有私有访问权限。
      • altMetafactory

        public static CallSite altMetafactory​(MethodHandles.Lookup caller,
                                              String invokedName,
                                              MethodType invokedType,
                                              Object... args)
                                       throws LambdaConversionException
        在适当的类型适配和参数的部分评估之后,通过委托给提供的MethodHandle ,促进创建实现一个或多个接口的简单“功能对象”。 通常用作invokedynamic调用站点的bootstrap方法 ,以支持Java编程语言的lambda表达式方法引用表达式功能。

        这是一般的,更灵活的metafactory; 精简版由metafactory(java.lang.invoke.MethodHandles.Lookup, String, MethodType, MethodType, MethodHandle, MethodType)提供。 above提供了该方法的一般描述。

        此方法的参数列表包括三个固定参数,对应于VM在invokedynamic调用中为引导方法自动堆叠的参数,以及包含其他参数的Object[]参数。 此方法的声明参数列表是:

           CallSite altMetafactory(MethodHandles.Lookup caller, String invokedName, MethodType invokedType, Object... args)  

        但它的行为就好像参数列表如下:

           CallSite altMetafactory(MethodHandles.Lookup caller, String invokedName, MethodType invokedType, MethodType samMethodType, MethodHandle implMethod, MethodType instantiatedMethodType, int flags, int markerInterfaceCount, // IF flags has MARKERS set Class... markerInterfaces, // IF flags has MARKERS set int bridgeCount, // IF flags has BRIDGES set MethodType... bridges // IF flags has BRIDGES set )  

        出现在metafactory(MethodHandles.Lookup, String, MethodType, MethodType, MethodHandle, MethodType)的参数列表中的参数与该方法中的规范相同。 附加参数解释如下:

        • flags表示其他选项; 这是所需标志的按位OR。 定义的标志为FLAG_BRIDGESFLAG_MARKERSFLAG_SERIALIZABLE
        • markerInterfaceCount是函数对象应实现的附加接口数,当且仅当设置了FLAG_MARKERS标志时才存在。
        • markerInterfaces是要实现的其他接口的可变长度列表,其长度等于markerInterfaceCount ,并且当且仅当FLAG_MARKERS标志置1时才存在。
        • bridgeCount是函数对象应实现的附加方法签名的数量,当且仅当设置了FLAG_BRIDGES标志时才存在。
        • bridges是要实现的其他方法签名的可变长度列表,其长度等于bridgeCount ,并且当且仅当设置了FLAG_BRIDGES标志时才存在。

        markerInterfaces命名的每个类受到与Rd相同的限制,返回类型invokedType ,如above所述。 每个MethodType由名为bridges受到相同的限制samMethodType ,如所描述above

        当在flags中设置flags ,函数对象将实现Serializable ,并且将具有返回适当的SerializedLambdawriteReplace方法。 caller类必须具有适当的$deserializeLambda$方法,如SerializedLambda中所述

        当调用从此方法返回的CallSite的目标时,生成的函数对象是具有以下属性的类的实例:

        • 该类实现由返回类型invokedType以及由markerInterfaces命名的任何接口命名的markerInterfaces
        • 该类声明方法,名称由invokedName给出,签名由samMethodType给出,附加签名由bridges给出
        • 该类可以覆盖Object方法,并且可以实现与序列化相关的方法。
        参数
        caller - 表示具有调用caller访问权限的查找上下文。 具体而言,查找上下文必须具有private access权限。 invokedynamic使用时,VM会自动堆叠。
        invokedName - 要实现的方法的名称。 当与invokedynamic使用时,这由InvokeDynamic结构的NameAndType提供,并由VM自动堆叠。
        invokedType -的的预期的签名CallSite 参数类型表示捕获变量的类型; 返回类型是要实现的接口。 当与invokedynamic使用时,这由InvokeDynamic结构的NameAndType提供,并由VM自动堆叠。 如果实现方法是实例方法并且此签名具有任何参数,则调用签名中的第一个参数必须对应于接收方。
        args -一个 Object[]含有所需参数阵列 samMethodTypeimplMethodinstantiatedMethodTypeflags ,和任何任选的参数,如所描述 altMetafactory(MethodHandles.Lookup, String, MethodType, Object...)以上}
        结果
        一个CallSite,其目标可用于执行捕获,生成由 invokedType命名的接口实例
        异常
        LambdaConversionException - If any of the linkage invariants described above are violated, or the lookup context does not have private access privileges.