LambdaMetafactory lambda元工厂
介绍
LambdaMetafactory
是Java在引入Lambda表达式后,为了在运行时动态生成和实例化Lambda表达式所对应的类而提供的一个工具。它是Java 8中引入的一部分,位于java.lang.invoke
包下。LambdaMetafactory
主要用于底层的Lambda表达式的实现机制,对于大多数Java开发者来说,是透明的,不需要直接使用。
主要功能
LambdaMetafactory
提供了一种机制,通过它可以将Lambda表达式转换为一个实现了函数式接口的类的实例。这个过程主要涉及到动态生成类和方法,并且这些类和方法在运行时被定义和加载。这一切都是通过调用LambdaMetafactory
的静态方法实现的,最核心的方法是metafactory
。
工作原理
当编译器遇到一个Lambda表达式时,它会生成调用LambdaMetafactory
的metafactory
方法的调用指令。这个方法接收关于Lambda表达式的目标类型、函数式接口方法的签名、Lambda体的实现方法的签名等信息。LambdaMetafactory
使用这些信息动态生成一个类,这个类实现了Lambda表达式的目标函数式接口,并且包含了Lambda体的实现。然后,它返回一个指向这个新生成的类实例的引用。
使用场景
对于大多数Java开发者而言,不需要直接与LambdaMetafactory
交互。Lambda表达式的编译和运行时转换都是自动完成的。然而,了解LambdaMetafactory
的存在和它的工作原理,对于深入理解Java中Lambda表达式的实现机制是有帮助的。对于需要在运行时动态生成和操作函数式接口实例的高级用例,比如某些框架或库的开发者,可能会直接使用LambdaMetafactory
。
源码
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.lang.invoke;
import java.io.Serializable;
import java.util.Arrays;
/**
* <p>Methods to facilitate the creation of simple "function objects" that
* implement one or more interfaces by delegation to a provided {@link MethodHandle},
* possibly after type adaptation and partial evaluation of arguments. These
* methods are typically used as <em>bootstrap methods</em> for {@code invokedynamic}
* call sites, to support the <em>lambda expression</em> and <em>method
* reference expression</em> features of the Java Programming Language.
*
* <p>Indirect access to the behavior specified by the provided {@code MethodHandle}
* proceeds in order through three phases:
* <ul>
* <li><em>Linkage</em> occurs when the methods in this class are invoked.
* They take as arguments an interface to be implemented (typically a
* <em>functional interface</em>, one with a single abstract method), a
* name and signature of a method from that interface to be implemented, a
* method handle describing the desired implementation behavior
* for that method, and possibly other additional metadata, and produce a
* {@link CallSite} whose target can be used to create suitable function
* objects. Linkage may involve dynamically loading a new class that
* implements the target interface. The {@code CallSite} can be considered a
* "factory" for function objects and so these linkage methods are referred
* to as "metafactories".</li>
*
* <li><em>Capture</em> occurs when the {@code CallSite}'s target is
* invoked, typically through an {@code invokedynamic} call site,
* producing a function object. This may occur many times for
* a single factory {@code CallSite}. Capture may involve allocation of a
* new function object, or may return an existing function object. The
* behavior {@code MethodHandle} may have additional parameters beyond those
* of the specified interface method; these are referred to as <em>captured
* parameters</em>, which must be provided as arguments to the
* {@code CallSite} target, and which may be early-bound to the behavior
* {@code MethodHandle}. The number of captured parameters and their types
* are determined during linkage.</li>
*
* <li><em>Invocation</em> occurs when an implemented interface method
* is invoked on a function object. This may occur many times for a single
* function object. The method referenced by the behavior {@code MethodHandle}
* is invoked with the captured arguments and any additional arguments
* provided on invocation, as if by {@link MethodHandle#invoke(Object...)}.</li>
* </ul>
*
* <p>It is sometimes useful to restrict the set of inputs or results permitted
* at invocation. For example, when the generic interface {@code Predicate<T>}
* is parameterized as {@code Predicate<String>}, the input must be a
* {@code String}, even though the method to implement allows any {@code Object}.
* At linkage time, an additional {@link MethodType} parameter describes the
* "instantiated" method type; on invocation, the arguments and eventual result
* are checked against this {@code MethodType}.
*
* <p>This class provides two forms of linkage methods: a standard version
* ({@link #metafactory(MethodHandles.Lookup, String, MethodType, MethodType, MethodHandle, MethodType)})
* using an optimized protocol, and an alternate version
* {@link #altMetafactory(MethodHandles.Lookup, String, MethodType, Object...)}).
* The alternate version is a generalization of the standard version, providing
* additional control over the behavior of the generated function objects via
* flags and additional arguments. The alternate version adds the ability to
* manage the following attributes of function objects:
*
* <ul>
* <li><em>Bridging.</em> It is sometimes useful to implement multiple
* variations of the method signature, involving argument or return type
* adaptation. This occurs when multiple distinct VM signatures for a method
* are logically considered to be the same method by the language. The
* flag {@code FLAG_BRIDGES} indicates that a list of additional
* {@code MethodType}s will be provided, each of which will be implemented
* by the resulting function object. These methods will share the same
* name and instantiated type.</li>
*
* <li><em>Multiple interfaces.</em> If needed, more than one interface
* can be implemented by the function object. (These additional interfaces
* are typically marker interfaces with no methods.) The flag {@code FLAG_MARKERS}
* indicates that a list of additional interfaces will be provided, each of
* which should be implemented by the resulting function object.</li>
*
* <li><em>Serializability.</em> The generated function objects do not
* generally support serialization. If desired, {@code FLAG_SERIALIZABLE}
* can be used to indicate that the function objects should be serializable.
* Serializable function objects will use, as their serialized form,
* instances of the class {@code SerializedLambda}, which requires additional
* assistance from the capturing class (the class described by the
* {@link MethodHandles.Lookup} parameter {@code caller}); see
* {@link SerializedLambda} for details.</li>
* </ul>
*
* <p>Assume the linkage arguments are as follows:
* <ul>
* <li>{@code invokedType} (describing the {@code CallSite} signature) has
* K parameters of types (D1..Dk) and return type Rd;</li>
* <li>{@code samMethodType} (describing the implemented method type) has N
* parameters, of types (U1..Un) and return type Ru;</li>
* <li>{@code implMethod} (the {@code MethodHandle} providing the
* implementation has M parameters, of types (A1..Am) and return type Ra
* (if the method describes an instance method, the method type of this
* method handle already includes an extra first argument corresponding to
* the receiver);</li>
* <li>{@code instantiatedMethodType} (allowing restrictions on invocation)
* has N parameters, of types (T1..Tn) and return type Rt.</li>
* </ul>
*
* <p>Then the following linkage invariants must hold:
* <ul>
* <li>Rd is an interface</li>
* <li>{@code implMethod} is a <em>direct method handle</em></li>
* <li>{@code samMethodType} and {@code instantiatedMethodType} have the same
* arity N, and for i=1..N, Ti and Ui are the same type, or Ti and Ui are
* both reference types and Ti is a subtype of Ui</li>
* <li>Either Rt and Ru are the same type, or both are reference types and
* Rt is a subtype of Ru</li>
* <li>K + N = M</li>
* <li>For i=1..K, Di = Ai</li>
* <li>For i=1..N, Ti is adaptable to Aj, where j=i+k</li>
* <li>The return type Rt is void, or the return type Ra is not void and is
* adaptable to Rt</li>
* </ul>
*
* <p>Further, at capture time, if {@code implMethod} corresponds to an instance
* method, and there are any capture arguments ({@code K > 0}), then the first
* capture argument (corresponding to the receiver) must be non-null.
*
* <p>A type Q is considered adaptable to S as follows:
* <table summary="adaptable types">
* <tr><th>Q</th><th>S</th><th>Link-time checks</th><th>Invocation-time checks</th></tr>
* <tr>
* <td>Primitive</td><td>Primitive</td>
* <td>Q can be converted to S via a primitive widening conversion</td>
* <td>None</td>
* </tr>
* <tr>
* <td>Primitive</td><td>Reference</td>
* <td>S is a supertype of the Wrapper(Q)</td>
* <td>Cast from Wrapper(Q) to S</td>
* </tr>
* <tr>
* <td>Reference</td><td>Primitive</td>
* <td>for parameter types: Q is a primitive wrapper and Primitive(Q)
* can be widened to S
* <br>for return types: If Q is a primitive wrapper, check that
* Primitive(Q) can be widened to S</td>
* <td>If Q is not a primitive wrapper, cast Q to the base Wrapper(S);
* for example Number for numeric types</td>
* </tr>
* <tr>
* <td>Reference</td><td>Reference</td>
* <td>for parameter types: S is a supertype of Q
* <br>for return types: none</td>
* <td>Cast from Q to S</td>
* </tr>
* </table>
*
* @apiNote These linkage methods are designed to support the evaluation
* of <em>lambda expressions</em> and <em>method references</em> in the Java
* Language. For every lambda expressions or method reference in the source code,
* there is a target type which is a functional interface. Evaluating a lambda
* expression produces an object of its target type. The recommended mechanism
* for evaluating lambda expressions is to desugar the lambda body to a method,
* invoke an invokedynamic call site whose static argument list describes the
* sole method of the functional interface and the desugared implementation
* method, and returns an object (the lambda object) that implements the target
* type. (For method references, the implementation method is simply the
* referenced method; no desugaring is needed.)
*
* <p>The argument list of the implementation method and the argument list of
* the interface method(s) may differ in several ways. The implementation
* methods may have additional arguments to accommodate arguments captured by
* the lambda expression; there may also be differences resulting from permitted
* adaptations of arguments, such as casting, boxing, unboxing, and primitive
* widening. (Varargs adaptations are not handled by the metafactories; these are
* expected to be handled by the caller.)
*
* <p>Invokedynamic call sites have two argument lists: a static argument list
* and a dynamic argument list. The static argument list is stored in the
* constant pool; the dynamic argument is pushed on the operand stack at capture
* time. The bootstrap method has access to the entire static argument list
* (which in this case, includes information describing the implementation method,
* the target interface, and the target interface method(s)), as well as a
* method signature describing the number and static types (but not the values)
* of the dynamic arguments and the static return type of the invokedynamic site.
*
* @implNote The implementation method is described with a method handle. In
* theory, any method handle could be used. Currently supported are direct method
* handles representing invocation of virtual, interface, constructor and static
* methods.
*/
public class LambdaMetafactory {
/** Flag for alternate metafactories indicating the lambda object
* must be serializable */
public static final int FLAG_SERIALIZABLE = 1 << 0;
/**
* Flag for alternate metafactories indicating the lambda object implements
* other marker interfaces
* besides Serializable
*/
public static final int FLAG_MARKERS = 1 << 1;
/**
* Flag for alternate metafactories indicating the lambda object requires
* additional bridge methods
*/
public static final int FLAG_BRIDGES = 1 << 2;
private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
private static final MethodType[] EMPTY_MT_ARRAY = new MethodType[0];
/**
* Facilitates the creation of simple "function objects" that implement one
* or more interfaces by delegation to a provided {@link MethodHandle},
* after appropriate type adaptation and partial evaluation of arguments.
* Typically used as a <em>bootstrap method</em> for {@code invokedynamic}
* call sites, to support the <em>lambda expression</em> and <em>method
* reference expression</em> features of the Java Programming Language.
*
* <p>This is the standard, streamlined metafactory; additional flexibility
* is provided by {@link #altMetafactory(MethodHandles.Lookup, String, MethodType, Object...)}.
* A general description of the behavior of this method is provided
* {@link LambdaMetafactory above}.
*
* <p>When the target of the {@code CallSite} returned from this method is
* invoked, the resulting function objects are instances of a class which
* implements the interface named by the return type of {@code invokedType},
* declares a method with the name given by {@code invokedName} and the
* signature given by {@code samMethodType}. It may also override additional
* methods from {@code Object}.
*
* @param caller Represents a lookup context with the accessibility
* privileges of the caller. When used with {@code invokedynamic},
* this is stacked automatically by the VM.
* @param invokedName The name of the method to implement. When used with
* {@code invokedynamic}, this is provided by the
* {@code NameAndType} of the {@code InvokeDynamic}
* structure and is stacked automatically by the VM.
* @param invokedType The expected signature of the {@code CallSite}. The
* parameter types represent the types of capture variables;
* the return type is the interface to implement. When
* used with {@code invokedynamic}, this is provided by
* the {@code NameAndType} of the {@code InvokeDynamic}
* structure and is stacked automatically by the VM.
* In the event that the implementation method is an
* instance method and this signature has any parameters,
* the first parameter in the invocation signature must
* correspond to the receiver.
* @param samMethodType Signature and return type of method to be implemented
* by the function object.
* @param implMethod A direct method handle describing the implementation
* method which should be called (with suitable adaptation
* of argument types, return types, and with captured
* arguments prepended to the invocation arguments) at
* invocation time.
* @param instantiatedMethodType The signature and return type that should
* be enforced dynamically at invocation time.
* This may be the same as {@code samMethodType},
* or may be a specialization of it.
* @return a CallSite whose target can be used to perform capture, generating
* instances of the interface named by {@code invokedType}
* @throws LambdaConversionException If any of the linkage invariants
* described {@link LambdaMetafactory above}
* are violated
*/
public static CallSite metafactory(MethodHandles.Lookup caller,
String invokedName,
MethodType invokedType,
MethodType samMethodType,
MethodHandle implMethod,
MethodType instantiatedMethodType)
throws LambdaConversionException {
AbstractValidatingLambdaMetafactory mf;
mf = new InnerClassLambdaMetafactory(caller, invokedType,
invokedName, samMethodType,
implMethod, instantiatedMethodType,
false, EMPTY_CLASS_ARRAY, EMPTY_MT_ARRAY);
mf.validateMetafactoryArgs();
return mf.buildCallSite();
}
/**
* Facilitates the creation of simple "function objects" that implement one
* or more interfaces by delegation to a provided {@link MethodHandle},
* after appropriate type adaptation and partial evaluation of arguments.
* Typically used as a <em>bootstrap method</em> for {@code invokedynamic}
* call sites, to support the <em>lambda expression</em> and <em>method
* reference expression</em> features of the Java Programming Language.
*
* <p>This is the general, more flexible metafactory; a streamlined version
* is provided by {@link #metafactory(java.lang.invoke.MethodHandles.Lookup,
* String, MethodType, MethodType, MethodHandle, MethodType)}.
* A general description of the behavior of this method is provided
* {@link LambdaMetafactory above}.
*
* <p>The argument list for this method includes three fixed parameters,
* corresponding to the parameters automatically stacked by the VM for the
* bootstrap method in an {@code invokedynamic} invocation, and an {@code Object[]}
* parameter that contains additional parameters. The declared argument
* list for this method is:
*
* <pre>{@code
* CallSite altMetafactory(MethodHandles.Lookup caller,
* String invokedName,
* MethodType invokedType,
* Object... args)
* }</pre>
*
* <p>but it behaves as if the argument list is as follows:
*
* <pre>{@code
* 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
* )
* }</pre>
*
* <p>Arguments that appear in the argument list for
* {@link #metafactory(MethodHandles.Lookup, String, MethodType, MethodType, MethodHandle, MethodType)}
* have the same specification as in that method. The additional arguments
* are interpreted as follows:
* <ul>
* <li>{@code flags} indicates additional options; this is a bitwise
* OR of desired flags. Defined flags are {@link #FLAG_BRIDGES},
* {@link #FLAG_MARKERS}, and {@link #FLAG_SERIALIZABLE}.</li>
* <li>{@code markerInterfaceCount} is the number of additional interfaces
* the function object should implement, and is present if and only if the
* {@code FLAG_MARKERS} flag is set.</li>
* <li>{@code markerInterfaces} is a variable-length list of additional
* interfaces to implement, whose length equals {@code markerInterfaceCount},
* and is present if and only if the {@code FLAG_MARKERS} flag is set.</li>
* <li>{@code bridgeCount} is the number of additional method signatures
* the function object should implement, and is present if and only if
* the {@code FLAG_BRIDGES} flag is set.</li>
* <li>{@code bridges} is a variable-length list of additional
* methods signatures to implement, whose length equals {@code bridgeCount},
* and is present if and only if the {@code FLAG_BRIDGES} flag is set.</li>
* </ul>
*
* <p>Each class named by {@code markerInterfaces} is subject to the same
* restrictions as {@code Rd}, the return type of {@code invokedType},
* as described {@link LambdaMetafactory above}. Each {@code MethodType}
* named by {@code bridges} is subject to the same restrictions as
* {@code samMethodType}, as described {@link LambdaMetafactory above}.
*
* <p>When FLAG_SERIALIZABLE is set in {@code flags}, the function objects
* will implement {@code Serializable}, and will have a {@code writeReplace}
* method that returns an appropriate {@link SerializedLambda}. The
* {@code caller} class must have an appropriate {@code $deserializeLambda$}
* method, as described in {@link SerializedLambda}.
*
* <p>When the target of the {@code CallSite} returned from this method is
* invoked, the resulting function objects are instances of a class with
* the following properties:
* <ul>
* <li>The class implements the interface named by the return type
* of {@code invokedType} and any interfaces named by {@code markerInterfaces}</li>
* <li>The class declares methods with the name given by {@code invokedName},
* and the signature given by {@code samMethodType} and additional signatures
* given by {@code bridges}</li>
* <li>The class may override methods from {@code Object}, and may
* implement methods related to serialization.</li>
* </ul>
*
* @param caller Represents a lookup context with the accessibility
* privileges of the caller. When used with {@code invokedynamic},
* this is stacked automatically by the VM.
* @param invokedName The name of the method to implement. When used with
* {@code invokedynamic}, this is provided by the
* {@code NameAndType} of the {@code InvokeDynamic}
* structure and is stacked automatically by the VM.
* @param invokedType The expected signature of the {@code CallSite}. The
* parameter types represent the types of capture variables;
* the return type is the interface to implement. When
* used with {@code invokedynamic}, this is provided by
* the {@code NameAndType} of the {@code InvokeDynamic}
* structure and is stacked automatically by the VM.
* In the event that the implementation method is an
* instance method and this signature has any parameters,
* the first parameter in the invocation signature must
* correspond to the receiver.
* @param args An {@code Object[]} array containing the required
* arguments {@code samMethodType}, {@code implMethod},
* {@code instantiatedMethodType}, {@code flags}, and any
* optional arguments, as described
* {@link #altMetafactory(MethodHandles.Lookup, String, MethodType, Object...)} above}
* @return a CallSite whose target can be used to perform capture, generating
* instances of the interface named by {@code invokedType}
* @throws LambdaConversionException If any of the linkage invariants
* described {@link LambdaMetafactory above}
* are violated
*/
public static CallSite altMetafactory(MethodHandles.Lookup caller,
String invokedName,
MethodType invokedType,
Object... args)
throws LambdaConversionException {
MethodType samMethodType = (MethodType)args[0];
MethodHandle implMethod = (MethodHandle)args[1];
MethodType instantiatedMethodType = (MethodType)args[2];
int flags = (Integer) args[3];
Class<?>[] markerInterfaces;
MethodType[] bridges;
int argIndex = 4;
if ((flags & FLAG_MARKERS) != 0) {
int markerCount = (Integer) args[argIndex++];
markerInterfaces = new Class<?>[markerCount];
System.arraycopy(args, argIndex, markerInterfaces, 0, markerCount);
argIndex += markerCount;
}
else
markerInterfaces = EMPTY_CLASS_ARRAY;
if ((flags & FLAG_BRIDGES) != 0) {
int bridgeCount = (Integer) args[argIndex++];
bridges = new MethodType[bridgeCount];
System.arraycopy(args, argIndex, bridges, 0, bridgeCount);
argIndex += bridgeCount;
}
else
bridges = EMPTY_MT_ARRAY;
boolean isSerializable = ((flags & FLAG_SERIALIZABLE) != 0);
if (isSerializable) {
boolean foundSerializableSupertype = Serializable.class.isAssignableFrom(invokedType.returnType());
for (Class<?> c : markerInterfaces)
foundSerializableSupertype |= Serializable.class.isAssignableFrom(c);
if (!foundSerializableSupertype) {
markerInterfaces = Arrays.copyOf(markerInterfaces, markerInterfaces.length + 1);
markerInterfaces[markerInterfaces.length-1] = Serializable.class;
}
}
AbstractValidatingLambdaMetafactory mf
= new InnerClassLambdaMetafactory(caller, invokedType,
invokedName, samMethodType,
implMethod,
instantiatedMethodType,
isSerializable,
markerInterfaces, bridges);
mf.validateMetafactoryArgs();
return mf.buildCallSite();
}
}
源码解释
package java.lang.invoke;
import java.io.Serializable;
import java.util.Arrays;
/**
* <p>用于简化创建简单的“函数对象”的方法,这些对象通过委托给提供的{@link MethodHandle}来实现一个或多个接口,
* 可能在类型适配和参数的部分求值之后。这些方法通常用作{@code invokedynamic}调用站点的<em>引导方法</em>,
* 以支持Java编程语言的<em>lambda表达式</em>和<em>方法引用表达式</em>特性。
*
* <p>通过三个阶段依次间接访问由提供的{@code MethodHandle}指定的行为:
* <ul>
* <li><em>链接</em>发生在调用此类中的方法时。
* 它们以要实现的接口(通常是一个具有单个抽象方法的<em>功能接口</em>)、要实现的接口方法的名称和签名、
* 描述该方法所需实现行为的方法句柄以及可能的其他附加元数据为参数,并产生一个{@link CallSite},
* 其目标可用于创建合适的函数对象。链接可能涉及动态加载实现目标接口的新类。{@code CallSite}可以被视为函数对象的“工厂”,
* 因此这些链接方法被称为“元工厂”。</li>
*
* <li><em>捕获</em>发生在调用{@code CallSite}的目标时,通常通过{@code invokedynamic}调用站点,
* 产生一个函数对象。对于单个工厂{@code CallSite},这可能发生多次。捕获可能涉及分配一个新的函数对象,
* 或可能返回一个现有的函数对象。行为{@code MethodHandle}可能有超出指定接口方法的额外参数;
* 这些被称为<em>捕获的参数</em>,必须作为参数提供给{@code CallSite}目标,并且可能被早期绑定到行为{@code MethodHandle}。
* 捕获的参数的数量和类型在链接期间确定。</li>
*
* <li><em>调用</em>发生在在函数对象上调用实现的接口方法时。对于单个函数对象,这可能发生多次。
* 由行为{@code MethodHandle}引用的方法与捕获的参数和调用时提供的任何额外参数一起被调用,就像通过{@link MethodHandle#invoke(Object...)}。</li>
* </ul>
*
* <p>有时限制调用时允许的输入或结果集是有用的。例如,当泛型接口{@code Predicate<T>}参数化为{@code Predicate<String>}时,
* 输入必须是一个{@code String},即使要实现的方法允许任何{@code Object}。在链接时,一个额外的{@link MethodType}参数描述了“实例化”的方法类型;
* 在调用时,参数和最终结果将根据这个{@code MethodType}进行检查。
*
* <p>此类提供了两种形式的链接方法:一个标准版本({@link #metafactory(MethodHandles.Lookup, String, MethodType, MethodType, MethodHandle, MethodType)})
* 使用优化的协议,和一个替代版本({@link #altMetafactory(MethodHandles.Lookup, String, MethodType, Object...)})。
* 替代版本是标准版本的泛化,通过标志和额外的参数提供对生成的函数对象的行为的额外控制。替代版本增加了管理函数对象以下属性的能力:
*
* <ul>
* <li><em>桥接。</em>有时实现方法签名的多个变体是有用的,涉及参数或返回类型的适配。
* 当一个方法的多个不同VM签名在语言中逻辑上被视为同一个方法时,就会发生这种情况。{@code FLAG_BRIDGES}标志表示将提供额外的
* {@code MethodType}列表,每个都将由结果函数对象实现。这些方法将共享相同的名称和实例化类型。</li>
*
* <li><em>多接口。</em>如果需要,函数对象可以实现多个接口。(这些额外的接口通常是没有方法的标记接口。)
* {@code FLAG_MARKERS}标志表示将提供额外的接口列表,每个接口都应由结果函数对象实现。</li>
*
* <li><em>可序列化性。</em>生成的函数对象通常不支持序列化。如果需要,可以使用{@code FLAG_SERIALIZABLE}标志来指示函数对象应该是可序列化的。
* 可序列化的函数对象将使用类{@code SerializedLambda}的实例作为其序列化形式,这需要捕获类(由{@link MethodHandles.Lookup}参数{@code caller}描述的类)的额外协助;
* 详见{@link SerializedLambda}。</li>
* </ul>
*
* <p>假设链接参数如下:
* <ul>
* <li>{@code invokedType}(描述{@code CallSite}签名)有K个类型为(D1..Dk)的参数和返回类型Rd;</li>
* <li>{@code samMethodType}(描述实现的方法类型)有N个参数,类型为(U1..Un)和返回类型Ru;</li>
* <li>{@code implMethod}(提供实现的{@code MethodHandle})有M个参数,类型为(A1..Am)和返回类型Ra
* (如果方法描述一个实例方法,这个方法句柄的方法类型已经包括了一个额外的第一个参数,对应于接收者);</li>
* <li>{@code instantiatedMethodType}(允许对调用进行限制)有N个参数,类型为(T1..Tn)和返回类型Rt。</li>
* </ul>
*
* <p>然后以下链接不变量必须成立:
* <ul>
* <li>Rd是一个接口</li>
* <li>{@code implMethod}是一个<em>直接方法句柄</em></li>
* <li>{@code samMethodType}和{@code instantiatedMethodType}有相同的元数N,对于i=1..N,Ti和Ui是相同的类型,
* 或Ti和Ui都是引用类型且Ti是Ui的子类型</li>
* <li>Rt和Ru要么是相同的类型,要么都是引用类型且Rt是Ru的子类型</li>
* <li>K + N = M</li>
* <li>对于i=1..K,Di = Ai</li>
* <li>对于i=1..N,Ti可以适配到Aj,其中j=i+k</li>
* <li>返回类型Rt是void,或返回类型Ra不是void且可以适配到Rt</li>
* </ul>
*
* <p>此外,在捕获时,如果{@code implMethod}对应于一个实例方法,并且有任何捕获参数({@code K > 0}),则第一个捕获参数(对应于接收者)必须非空。
*
* <p>类型Q被认为可以适配到S如下:
* <table summary="可适配类型">
* <tr><th>Q</th><th>S</th><th>链接时检查</th><th>调用时检查</th></tr>
* <tr>
* <td>原始</td><td>原始</td>
* <td>Q可以通过原始类型扩宽转换转换为S</td>
* <td>无</td>
* </tr>
* <tr>
* <td>原始</td><td>引用</td>
* <td>S是Wrapper(Q)的超类型</td>
* <td>从Wrapper(Q)转型到S</td>
* </tr>
* <tr>
* <td>引用</td><td>原始</td>
* <td>对于参数类型:Q是原始包装器并且Primitive(Q)可以扩宽到S
* <br>对于返回类型:如果Q是原始包装器,检查Primitive(Q)是否可以扩宽到S</td>
* <td>如果Q不是原始包装器,将Q转型为基本Wrapper(S);
* 例如对于数值类型为Number</td>
* </tr>
* <tr>
* <td>引用</td><td>引用</td>
* <td>对于参数类型:S是Q的超类型
* <br>对于返回类型:无</td>
* <td>从Q转型到S</td>
* </tr>
* </table>
*
* @apiNote 这些链接方法旨在支持Java语言中<em>lambda表达式</em>和<em>方法引用</em>的评估。
* 对于源代码中的每个lambda表达式或方法引用,都有一个目标类型,即功能接口。评估lambda表达式会产生其目标类型的对象。
* 评估lambda表达式的推荐机制是将lambda体糖化为一个方法,调用一个invokedynamic调用站点,其静态参数列表描述了功能接口的唯一方法和糖化的实现方法,
* 并返回一个实现目标类型的对象(lambda对象)。(对于方法引用,实现方法简单地是引用的方法;不需要糖化。)
*
* <p>实现方法的参数列表和接口方法的参数列表可能在几个方面不同。实现方法可能有额外的参数来适应lambda表达式捕获的参数;
* 还可能有由于允许的参数适配而产生的差异,如类型转换、装箱、拆箱和原始类型扩宽。(Varargs适配不由元工厂处理;这些预期由调用者处理。)
*
* <p>Invokedynamic调用站点有两个参数列表:一个静态参数列表和一个动态参数列表。静态参数列表存储在常量池中;
* 动态参数在捕获时推送到操作数栈上。引导方法可以访问整个静态参数列表(在这种情况下,包括描述实现方法、目标接口和目标接口方法的信息),
* 以及一个方法签名,描述了invokedynamic站点的动态参数的数量和静态类型(但不是值)和静态返回类型。
*
* @implNote 实现方法用方法句柄描述。理论上,任何方法句柄都可以使用。当前支持的是直接方法句柄,代表调用虚拟、接口、构造器和静态方法。
*/
public class LambdaMetafactory {
/**
* 这个标志用于指示生成的lambda对象必须是可序列化的。其值为1 << 0,即1,表示将数字1左移0位,其结果仍然是1。这是通过位运算来设置标志位的一种常见方式。
* */
public static final int FLAG_SERIALIZABLE = 1 << 0;
/**
* 这个标志用于指示lambda对象除了Serializable接口外,还实现了其他标记接口(marker interfaces)。其值为1 << 1,即2,表示将数字1左移1位,结果是2。这允许lambda对象可以被视为实现了额外的接口。
*/
public static final int FLAG_MARKERS = 1 << 1;
/**
* 这个标志用于指示lambda对象需要额外的桥接方法(bridge methods)。其值为1 << 2,即4,表示将数字1左移2位,结果是4。桥接方法用于解决泛型擦除后的方法重载问题。
*/
public static final int FLAG_BRIDGES = 1 << 2;
/**
* 这是一个空的Class<?>类型数组,用于在不需要类数组作为参数时提供一个默认值,避免null的使用。这样可以减少空指针异常的风险。
*/
private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
/**
* 这是一个空的MethodType[]类型数组,用于在不需要方法类型数组作为参数时提供一个默认值。MethodType是Java中表示方法签名的类,这个空数组同样用于避免null的使用
*/
private static final MethodType[] EMPTY_MT_ARRAY = new MethodType[0];
/**
* 为了支持Java编程语言中的ambda表达式和方法引用表达式特性,
* 本方法提供了一种简便的方式来创建实现一个或多个接口的“函数对象”。这些函数对象是通过委托给一个提供的{@link MethodHandle},
* 在适当的类型适配和参数的部分求值之后实现的。通常作为{@code invokedynamic}调用点的<em>引导方法</em>使用。
*
* <p>这是标准的、简化的元工厂方法;通过{@link #altMetafactory(MethodHandles.Lookup, String, MethodType, Object...)}
* 提供了额外的灵活性。关于此方法的行为的一般描述,请参见{@link LambdaMetafactory}。
*
* <p>当从此方法返回的{@code CallSite}的目标被调用时,生成的函数对象是实现由{@code invokedType}的返回类型命名的接口的类的实例,
* 声明了一个具有由{@code invokedName}和{@code samMethodType}给出的名称和签名的方法。它还可能覆盖来自{@code Object}的额外方法。
*
* @param caller 表示具有调用者访问权限的查找上下文。当与{@code invokedynamic}一起使用时,这由VM自动堆叠。
* @param invokedName 要实现的方法的名称。当与{@code invokedynamic}一起使用时,这由{@code InvokeDynamic}结构的{@code NameAndType}提供,并由VM自动堆叠。
* @param invokedType {@code CallSite}的预期签名。参数类型代表捕获变量的类型;返回类型是要实现的接口。当与{@code invokedynamic}一起使用时,这由{@code InvokeDynamic}结构的{@code NameAndType}提供,并由VM自动堆叠。如果实现方法是实例方法并且此签名有任何参数,则调用签名中的第一个参数必须对应于接收者。
* @param samMethodType 函数对象要实现的方法的签名和返回类型。
* @param implMethod 描述应在调用时调用的实现方法的直接方法句柄(适当地适配参数类型、返回类型,并将捕获的参数前置到调用参数中)。
* @param instantiatedMethodType 应在调用时动态强制执行的签名和返回类型。这可能与{@code samMethodType}相同,或可能是其特化版本。
* @return 一个CallSite,其目标可用于执行捕获,生成由{@code invokedType}命名的接口的实例
* @throws LambdaConversionException 如果违反了{@link LambdaMetafactory}中描述的任何链接不变量
*/
public static CallSite metafactory(MethodHandles.Lookup caller,
String invokedName,
MethodType invokedType,
MethodType samMethodType,
MethodHandle implMethod,
MethodType instantiatedMethodType)
throws LambdaConversionException {
// 创建一个内部类Lambda元工厂实例,用于生成和验证lambda表达式的实现
AbstractValidatingLambdaMetafactory mf;
mf = new InnerClassLambdaMetafactory(caller, invokedType,
invokedName, samMethodType,
implMethod, instantiatedMethodType,
false, EMPTY_CLASS_ARRAY, EMPTY_MT_ARRAY);
// 验证元工厂方法的参数是否符合要求
mf.validateMetafactoryArgs();
// 构建并返回一个CallSite,它是lambda表达式或方法引用的动态调用点
return mf.buildCallSite();
}
/**
* 提供了一个更通用、更灵活的元工厂方法,用于创建简单的“函数对象”,这些对象通过委托给一个指定的{@link MethodHandle}来实现一个或多个接口,
* 在适当的类型适配和参数的部分求值之后。这通常被用作{@code invokedynamic}调用站点的<em>引导方法</em>,
* 以支持Java编程语言的<em>lambda表达式</em>和<em>方法引用表达式</em>特性。
*
* <p>这是一个通用的、更灵活的元工厂方法;一个更简化的版本由{@link #metafactory(java.lang.invoke.MethodHandles.Lookup,
* String, MethodType, MethodType, MethodHandle, MethodType)}提供。此方法的行为的一般描述在{@link LambdaMetafactory}上方提供。
*
* <p>此方法的参数列表包括三个固定参数,对应于VM为{@code invokedynamic}调用中的引导方法自动堆叠的参数,
* 以及一个包含额外参数的{@code Object[]}参数。声明的参数列表为:
*
* <pre>{@code
* CallSite altMetafactory(MethodHandles.Lookup caller,
* String invokedName,
* MethodType invokedType,
* Object... args)
* }</pre>
*
* <p>但它的行为就好像参数列表是如下所示:
*
* <pre>{@code
* CallSite altMetafactory(MethodHandles.Lookup caller,
* String invokedName,
* MethodType invokedType,
* MethodType samMethodType,
* MethodHandle implMethod,
* MethodType instantiatedMethodType,
* int flags,
* int markerInterfaceCount, // 如果flags设置了MARKERS
* Class... markerInterfaces, // 如果flags设置了MARKERS
* int bridgeCount, // 如果flags设置了BRIDGES
* MethodType... bridges // 如果flags设置了BRIDGES
* )
* }</pre>
*
* <p>在{@link #metafactory(MethodHandles.Lookup, String, MethodType, MethodType, MethodHandle, MethodType)}
* 的参数列表中出现的参数具有相同的规范。额外的参数如下解释:
* <ul>
* <li>{@code flags} 表示额外的选项;这是所需标志的按位OR。定义的标志有{@link #FLAG_BRIDGES}、
* {@link #FLAG_MARKERS}和{@link #FLAG_SERIALIZABLE}。</li>
* <li>{@code markerInterfaceCount} 是函数对象应该实现的额外接口的数量,仅当{@code FLAG_MARKERS}标志被设置时出现。</li>
* <li>{@code markerInterfaces} 是一个变长列表,包含要实现的额外接口,其长度等于{@code markerInterfaceCount},
* 仅当{@code FLAG_MARKERS}标志被设置时出现。</li>
* <li>{@code bridgeCount} 是函数对象应该实现的额外方法签名的数量,仅当{@code FLAG_BRIDGES}标志被设置时出现。</li>
* <li>{@code bridges} 是一个变长列表,包含要实现的额外方法签名,其长度等于{@code bridgeCount},
* 仅当{@code FLAG_BRIDGES}标志被设置时出现。</li>
* </ul>
*
* <p>每个由{@code markerInterfaces}命名的类都受到与{@code invokedType}的返回类型{@code Rd}相同的限制,
* 如{@link LambdaMetafactory}上方所述。每个由{@code bridges}命名的{@code MethodType}都受到与
* {@code samMethodType}相同的限制,如{@link LambdaMetafactory}上方所述。
*
* <p>当在{@code flags}中设置了FLAG_SERIALIZABLE时,函数对象将实现{@code Serializable},
* 并且将有一个返回适当的{@link SerializedLambda}的{@code writeReplace}方法。
* {@code caller}类必须有一个适当的{@code $deserializeLambda$}方法,如{@link SerializedLambda}中所述。
*
* <p>当从此方法返回的{@code CallSite}的目标被调用时,生成的函数对象是一个类的实例,具有以下属性:
* <ul>
* <li>该类实现了{@code invokedType}的返回类型命名的接口和任何由{@code markerInterfaces}命名的接口</li>
* <li>该类声明了具有{@code invokedName}给出的名称的方法,以及{@code samMethodType}和{@code bridges}给出的额外签名的方法</li>
* <li>该类可能覆盖来自{@code Object}的方法,并可能实现与序列化相关的方法。</li>
* </ul>
*
* @param caller 代表具有调用者访问权限特权的查找上下文。当与{@code invokedynamic}一起使用时,这由VM自动堆叠。
* @param invokedName 要实现的方法的名称。当与{@code invokedynamic}一起使用时,这由{@code InvokeDynamic}结构的{@code NameAndType}提供,并由VM自动堆叠。
* @param invokedType {@code CallSite}的预期签名。参数类型代表捕获变量的类型;返回类型是要实现的接口。当与{@code invokedynamic}一起使用时,这由{@code InvokeDynamic}结构的{@code NameAndType}提供,并由VM自动堆叠。如果实现方法是一个实例方法并且此签名有任何参数,那么调用签名中的第一个参数必须对应于接收者。
* @param args 一个{@code Object[]}数组,包含所需的参数{@code samMethodType}、{@code implMethod}、{@code instantiatedMethodType}、{@code flags},以及任何可选参数,如上文{@link #altMetafactory(MethodHandles.Lookup, String, MethodType, Object...)}所述
* @return 一个CallSite,其目标可用于执行捕获,生成由{@code invokedType}命名的接口的实例
* @throws LambdaConversionException 如果违反了{@link LambdaMetafactory}上方描述的链接不变量
*/
public static CallSite altMetafactory(MethodHandles.Lookup caller,
String invokedName,
MethodType invokedType,
Object... args)
throws LambdaConversionException {
// 解析参数:SAM方法类型
MethodType samMethodType = (MethodType)args[0];
// 解析参数:实现方法的方法句柄
MethodHandle implMethod = (MethodHandle)args[1];
// 解析参数:实例化方法类型
MethodType instantiatedMethodType = (MethodType)args[2];
// 解析参数:标志位,用于指示额外的选项
int flags = (Integer) args[3];
Class<?>[] markerInterfaces;
MethodType[] bridges;
int argIndex = 4;
// 如果设置了FLAG_MARKERS标志,解析标记接口
if ((flags & FLAG_MARKERS) != 0) {
int markerCount = (Integer) args[argIndex++];
markerInterfaces = new Class<?>[markerCount];
System.arraycopy(args, argIndex, markerInterfaces, 0, markerCount);
argIndex += markerCount;
}
else
markerInterfaces = EMPTY_CLASS_ARRAY;
// 如果设置了FLAG_BRIDGES标志,解析桥接方法类型
if ((flags & FLAG_BRIDGES) != 0) {
int bridgeCount = (Integer) args[argIndex++];
bridges = new MethodType[bridgeCount];
System.arraycopy(args, argIndex, bridges, 0, bridgeCount);
argIndex += bridgeCount;
}
else
bridges = EMPTY_MT_ARRAY;
// 检查是否需要序列化
boolean isSerializable = ((flags & FLAG_SERIALIZABLE) != 0);
if (isSerializable) {
// 检查返回类型或标记接口是否已经可序列化
boolean foundSerializableSupertype = Serializable.class.isAssignableFrom(invokedType.returnType());
for (Class<?> c : markerInterfaces)
foundSerializableSupertype |= Serializable.class.isAssignableFrom(c);
// 如果没有找到可序列化的超类型,添加Serializable接口
if (!foundSerializableSupertype) {
markerInterfaces = Arrays.copyOf(markerInterfaces, markerInterfaces.length + 1);
markerInterfaces[markerInterfaces.length-1] = Serializable.class;
}
}
// 创建并初始化LambdaMetafactory对象
AbstractValidatingLambdaMetafactory mf
= new InnerClassLambdaMetafactory(caller, invokedType,
invokedName, samMethodType,
implMethod,
instantiatedMethodType,
isSerializable,
markerInterfaces, bridges);
// 验证metafactory参数
mf.validateMetafactoryArgs();
// 构建并返回CallSite对象
return mf.buildCallSite();
}
}