Module  java.base
软件包  java.lang.invoke

Class LambdaMetafactory



  • public final class LambdaMetafactory
    extends Object

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

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

    • 当调用此类中的方法时,会发生链接 它们将要实现的接口(通常是功能接口 ,具有单个抽象方法的接口 ),从要实现的接口的方法的名称和签名,描述该方法的所需实现行为的方法句柄,以及可能还有其他的元数据,并产生一个CallSite其目标可以用于创建合适的功能对象。 链接可能涉及动态加载实现目标接口的新类。 CallSite可以被认为是功能对象的“工厂”,因此这些连接方法被称为“元件”。
    • CallSite的目标被调用时,通常通过invokedynamic调用站点生成一个函数对象,就会发生捕获 对于单个工厂可能会发生多次CallSite Capture可能涉及分配一个新的函数对象,或者可能返回一个现有的函数对象。 行为MethodHandle可能具有超出指定接口方法的附加参数; 这些被称为捕获参数 ,它们必须作为CallSite目标的参数提供,并且可能早于行为MethodHandle 在联动期间确定捕获的参数及其类型的数量。
    • 当实现的接口方法的功能对象调用发生调用 对于单个函数对象可能会发生多次。 使用捕获的参数和调用时提供的任何其他参数调用由行为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签名)具有类型(D1..Dk)和返回类型Rd的K个参数;
    • samMethodType (描述实现的方法类型)具有N个参数,类型(U1..Un)和返回类型Ru;
    • implMethodMethodHandle提供的实现具有M个参数,类型(A1..Am)和返回类型Ra(如果该方法描述了一个实例方法,此方法句柄的方法类型已经包含与接收器对应的额外的第一个参数) ;
    • instantiatedMethodType (允许调用限制)具有N个参数,类型(T1..Tn)和返回类型Rt。

    那么以下链接不变量必须保持:

    • Rd是一个接口
    • implMethod是一种直接方法句柄
    • samMethodTypeinstantiatedMethodType具有相同的instantiatedMethodType 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不为空,并且适用于Rt

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

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

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

      • FLAG_SERIALIZABLE

        public static final int FLAG_SERIALIZABLE
        指示lambda对象的替代元素的标志必须是可序列化的
        另请参见:
        Constant Field Values
      • FLAG_MARKERS

        public static final int FLAG_MARKERS
        指示lambda对象的替代元素的标志实现除Serializable之外的其他标记接口
        另请参见:
        Constant Field Values
      • FLAG_BRIDGES

        public static final int FLAG_BRIDGES
        指示lambda对象的备用元素的标志需要额外的桥接方法
        另请参见:
        Constant Field Values
    • 方法详细信息

      • metafactory

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

        这是标准的流线型meta factory; 额外的灵活性由altMetafactory(MethodHandles.Lookup, String, MethodType, Object...)提供。 above提供了该方法的一般描述。

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

        参数
        caller - 表示具有调用者的辅助功能权限的查找上下文。 当与invokedynamic使用时,VM将自动堆叠。
        invokedName - 要实现的方法的名称。 invokedynamic使用时,由NameAndTypeInvokeDynamic提供,并由VM自动堆叠。
        invokedType -的的预期的签名CallSite 参数类型表示捕获变量的类型; 返回类型是要实现的接口。 invokedynamic使用时,由NameAndTypeInvokeDynamic提供,由VM自动堆叠。 在实现方法是实例方法且该签名具有任何参数的情况下,调用签名中的第一个参数必须对应于接收方。
        samMethodType - 由函数对象执行的方法的签名和返回类型。
        implMethod - 一个直接方法句柄,用于描述在调用时应该调用的实现方法(在参数类型,返回类型以及调用参数前面带有捕获参数的适当适配)。
        instantiatedMethodType - 在调用时动态执行的签名和返回类型。 这可能与samMethodType相同,或可能是其专业化。
        结果
        一个CallSite,其目标可以用于执行捕获,生成由 invokedType命名的接口的 invokedType
        异常
        LambdaConversionException - 如果违反了描述的任何链接不变量above
      • altMetafactory

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

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

        该方法的参数列表包括三个固定参数,对应于由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_MARKERS ,并FLAG_SERIALIZABLE
        • markerInterfaceCount是函数对象应该实现的附加接口的数量,并且当且仅当设置了FLAG_MARKERS标志时才存在。
        • markerInterfaces是要实现的附加接口的可变长度列表,其长度等于markerInterfaceCount ,并且当且仅当设置了FLAG_MARKERS标志时才存在。
        • 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命名的任何接口
        • 这个类声明与定名为方法invokedName ,用特定的签名samMethodType给出的和额外的签名bridges
        • 该类可以覆盖Object方法,并且可以实现与序列化相关的方法。
        参数
        caller - 表示具有调用者的辅助功能权限的查找上下文。 当与invokedynamic使用时,VM将自动堆叠。
        invokedName - 要实现的方法的名称。 当与invokedynamic使用时,由NameAndTypeInvokeDynamic提供,并由VM自动堆叠。
        invokedType -的的预期的签名CallSite 参数类型表示捕获变量的类型; 返回类型是要实现的接口。 当与invokedynamic使用时,由NameAndTypeInvokeDynamic提供,并由VM自动堆叠。 在实现方法是实例方法且该签名具有任何参数的情况下,调用签名中的第一个参数必须对应于接收方。
        args -一个 Object[]含有所需参数阵列 samMethodTypeimplMethodinstantiatedMethodTypeflags ,和任何任选的参数,如所描述 altMetafactory(MethodHandles.Lookup, String, MethodType, Object...)以上}
        结果
        一个CallSite,其目标可以用于执行捕获,生成由 invokedType命名的接口的 invokedType
        异常
        LambdaConversionException - If any of the linkage invariants described above are violated