java.lang.invoke.MethodHandle.asVarargsCollector()方法的使用及代码示例

x33g5p2x  于2022-01-24 转载在 其他  
字(19.2k)|赞(0)|评价(0)|浏览(126)

本文整理了Java中java.lang.invoke.MethodHandle.asVarargsCollector()方法的一些代码示例,展示了MethodHandle.asVarargsCollector()的具体用法。这些代码示例主要来源于Github/Stackoverflow/Maven等平台,是从一些精选项目中提取出来的代码,具有较强的参考意义,能在一定程度帮忙到你。MethodHandle.asVarargsCollector()方法的具体详情如下:
包路径:java.lang.invoke.MethodHandle
类名称:MethodHandle
方法名:asVarargsCollector

MethodHandle.asVarargsCollector介绍

[英]Makes a variable arity adapter which is able to accept any number of trailing positional arguments and collect them into an array argument.

The type and behavior of the adapter will be the same as the type and behavior of the target, except that certain invoke and asType requests can lead to trailing positional arguments being collected into target's trailing parameter. Also, the last parameter type of the adapter will be arrayType, even if the target has a different last parameter type.

This transformation may return this if the method handle is already of variable arity and its trailing parameter type is identical to arrayType.

When called with #invokeExact, the adapter invokes the target with no argument changes. (Note: This behavior is different from a #asCollector, since it accepts a whole array of indeterminate length, rather than a fixed number of arguments.)

When called with plain, inexact #invoke, if the caller type is the same as the adapter, the adapter invokes the target as with invokeExact. (This is the normal behavior for invoke when types match.)

Otherwise, if the caller and adapter arity are the same, and the trailing parameter type of the caller is a reference type identical to or assignable to the trailing parameter type of the adapter, the arguments and return values are converted pairwise, as if by #asType on a fixed arity method handle.

Otherwise, the arities differ, or the adapter's trailing parameter type is not assignable from the corresponding caller type. In this case, the adapter replaces all trailing arguments from the original trailing argument position onward, by a new array of type arrayType, whose elements comprise (in order) the replaced arguments.

The caller type must provides as least enough arguments, and of the correct type, to satisfy the target's requirement for positional arguments before the trailing array argument. Thus, the caller must supply, at a minimum, N-1 arguments, where N is the arity of the target. Also, there must exist conversions from the incoming arguments to the target's arguments. As with other uses of plain invoke, if these basic requirements are not fulfilled, a WrongMethodTypeExceptionmay be thrown.

In all cases, what the target eventually returns is returned unchanged by the adapter.

In the final case, it is exactly as if the target method handle were temporarily adapted with a #asCollectorto the arity required by the caller type. (As with asCollector, if the array length is zero, a shared constant may be used instead of a new array. If the implied call to asCollector would throw an IllegalArgumentException or WrongMethodTypeException, the call to the variable arity adapter must throw WrongMethodTypeException.)

The behavior of #asType is also specialized for variable arity adapters, to maintain the invariant that plain, inexact invoke is always equivalent to an asTypecall to adjust the target type, followed by invokeExact. Therefore, a variable arity adapter responds to an asType request by building a fixed arity collector, if and only if the adapter and requested type differ either in arity or trailing argument type. The resulting fixed arity collector has its type further adjusted (if necessary) to the requested type by pairwise conversion, as if by another application of asType.

When a method handle is obtained by executing an ldc instruction of a CONSTANT_MethodHandle constant, and the target method is marked as a variable arity method (with the modifier bit 0x0080), the method handle will accept multiple arities, as if the method handle constant were created by means of a call to asVarargsCollector.

In order to create a collecting adapter which collects a predetermined number of arguments, and whose type reflects this predetermined number, use #asCollector instead.

No method handle transformations produce new method handles with variable arity, unless they are documented as doing so. Therefore, besides asVarargsCollector, all methods in MethodHandle and MethodHandleswill return a method handle with fixed arity, except in the cases where they are specified to return their original operand (e.g., asType of the method handle's own type).

Calling asVarargsCollector on a method handle which is already of variable arity will produce a method handle with the same type and behavior. It may (or may not) return the original variable arity method handle.

Here is an example, of a list-making variable arity method handle:

MethodHandle deepToString = publicLookup()assertEquals("[won]",   (String) ts1.invokeExact(    new Object[]{"won"})); 
assertEquals("[won]",   (String) ts1.invoke(         new Object[]{"won"})); 
assertEquals("[won]",   (String) ts1.invoke(                      "won" )); 
assertEquals("[[won]]", (String) ts1.invoke((Object) new Object[]{"won"})); 
// findStatic of Arrays.asList(...) produces a variable arity method handle: 
MethodHandle asList = publicLookup() 
.findStatic(Arrays.class, "asList", methodType(List.class, Object[].class)); 
assertEquals(methodType(List.class, Object[].class), asList.type()); 
assert(asList.isVarargsCollector()); 
assertEquals("[]", asList.invoke().toString()); 
assertEquals("[1]", asList.invoke(1).toString()); 
assertEquals("[two, too]", asList.invoke("two", "too").toString()); 
String[] argv = { "three", "thee", "tee" }; 
assertEquals("[three, thee, tee]", asList.invoke(argv).toString()); 
assertEquals("[three, thee, tee]", asList.invoke((Object[])argv).toString()); 
List ls = (List) asList.invoke((Object)argv); 
assertEquals(1, ls.size()); 
assertEquals("[three, thee, tee]", Arrays.toString((Object[])ls.get(0))); 
}

Discussion: These rules are designed as a dynamically-typed variation of the Java rules for variable arity methods. In both cases, callers to a variable arity method or method handle can either pass zero or more positional arguments, or else pass pre-collected arrays of any length. Users should be aware of the special role of the final argument, and of the effect of a type match on that final argument, which determines whether or not a single trailing argument is interpreted as a whole array or a single element of an array to be collected. Note that the dynamic type of the trailing argument has no effect on this decision, only a comparison between the symbolic type descriptor of the call site and the type descriptor of the method handle.)
[中]生成一个variable arity适配器,该适配器能够接受任意数量的尾随位置参数,并将它们收集到一个数组参数中。
适配器的类型和行为将与目标的类型和行为相同,只是某些invoke和asType请求可能会导致将尾部位置参数收集到目标的尾部参数中。此外,适配器的最后一个参数类型将是arrayType,即使目标具有不同的最后一个参数类型。
如果方法句柄已经是变量arity,并且其尾部参数类型与arrayType相同,则此转换可能会返回此值。
当使用#invokeExact调用时,适配器调用目标而不改变参数。(*注意:*此行为不同于#asCollector,因为它接受整个长度不确定的数组,而不是固定数量的参数。)
当使用简单、不精确的#invoke调用时,如果调用方类型与适配器相同,那么适配器将像invokeExact一样调用目标。(这是类型匹配时调用的正常行为。)
否则,如果调用者和适配器的arity相同,并且调用者的尾部参数类型是与适配器的尾部参数类型相同或可分配给后者的引用类型,则参数和返回值将成对转换,就像通过固定arity方法句柄上的#asType一样。
否则,算术数不同,或者适配器的尾部参数类型不可从相应的调用方类型分配。在这种情况下,适配器将从原始尾随参数位置开始的所有尾随参数替换为arrayType类型的新数组,其元素(按顺序)包含替换的参数。
调用者类型必须至少提供足够的参数,且参数类型正确,以满足目标对尾随数组参数之前的位置参数的要求。因此,调用方必须至少提供N-1个参数,其中N是目标的算术数。此外,必须存在从传入参数到目标参数的转换。与普通调用的其他用法一样,如果没有满足这些基本要求,可能会抛出错误的MethodTypeException。
在所有情况下,目标最终返回的内容都会由适配器原封不动地返回。
在最后一种情况下,就好像目标方法句柄是用#asCollector临时调整的,以适应调用者类型所需的arity。(与asCollector一样,如果数组长度为零,则可以使用共享常量代替新数组。如果对asCollector的隐含调用将引发IllegalArgumentException或ErrorMethodTypeException,则对变量arity适配器的调用必须引发ErrorMethodTypeException。)
#asType的行为也专门用于变量arity适配器,以保持不变,即普通的、不精确的调用始终等同于asTypecall来调整目标类型,然后是invokeExact。因此,当且仅当适配器和请求的类型在arity或尾部参数类型上不同时,变量arity适配器通过构建固定arity收集器来响应asType请求。生成的固定arity收集器通过两两转换将其类型进一步调整(如有必要)为请求的类型,就像通过asType的另一个应用程序一样。
当通过执行常量\u MethodHandle常量的ldc指令获得方法句柄,并且目标方法被标记为变量arity方法(修改器位为0x0080)时,方法句柄将接受多个arity,就好像方法句柄常量是通过调用asVarargsCollector创建的一样。
为了创建一个收集预定数量参数的收集适配器,并且其类型反映了这个预定数量,请改用#asCollector。
任何方法句柄转换都不会生成具有变量arity的新方法句柄,除非它们被记录为这样做。因此,除了asVarargsCollector之外,MethodHandle和MethodHandles中的所有方法都将返回具有固定算术数的方法句柄,除非指定它们返回其原始操作数(例如,方法句柄自身类型的类型)。
对已具有变量arity的方法句柄调用asVarargsCollector将生成具有相同类型和行为的方法句柄。它可能(也可能不)返回原始变量arity方法句柄。
下面是一个列表生成变量arity方法句柄的示例:

MethodHandle deepToString = publicLookup()assertEquals("[won]",   (String) ts1.invokeExact(    new Object[]{"won"})); 
assertEquals("[won]",   (String) ts1.invoke(         new Object[]{"won"})); 
assertEquals("[won]",   (String) ts1.invoke(                      "won" )); 
assertEquals("[[won]]", (String) ts1.invoke((Object) new Object[]{"won"})); 
// findStatic of Arrays.asList(...) produces a variable arity method handle: 
MethodHandle asList = publicLookup() 
.findStatic(Arrays.class, "asList", methodType(List.class, Object[].class)); 
assertEquals(methodType(List.class, Object[].class), asList.type()); 
assert(asList.isVarargsCollector()); 
assertEquals("[]", asList.invoke().toString()); 
assertEquals("[1]", asList.invoke(1).toString()); 
assertEquals("[two, too]", asList.invoke("two", "too").toString()); 
String[] argv = { "three", "thee", "tee" }; 
assertEquals("[three, thee, tee]", asList.invoke(argv).toString()); 
assertEquals("[three, thee, tee]", asList.invoke((Object[])argv).toString()); 
List ls = (List) asList.invoke((Object)argv); 
assertEquals(1, ls.size()); 
assertEquals("[three, thee, tee]", Arrays.toString((Object[])ls.get(0))); 
}

*讨论:*这些规则被设计为变量arity方法的Java规则的动态类型变体。在这两种情况下,变量arity方法或方法句柄的调用方可以传递零个或多个位置参数,或者传递任意长度的预收集数组。用户应该知道最终参数的特殊作用,以及类型匹配对最终参数的影响,它决定了单个尾随参数是解释为整个数组还是要收集的数组的单个元素。请注意,尾随参数的动态类型对这个决定没有影响,只是比较了调用站点的符号类型描述符和方法句柄的类型描述符。)

代码示例

代码示例来源:origin: prestodb/presto

@Override
public ScalarFunctionImplementation specialize(BoundVariables boundVariables, int arity, TypeManager typeManager, FunctionRegistry functionRegistry)
{
  List<Type> types = this.typeParameters.stream().map(boundVariables::getTypeVariable).collect(toImmutableList());
  List<ArgumentProperty> argumentProperties = nCopies(types.size(), valueTypeArgumentProperty(RETURN_NULL_ON_NULL));
  List<Class<?>> javaArgumentTypes = nCopies(types.size(), Block.class);
  MethodHandle methodHandle = METHOD_HANDLE.bindTo(types).asVarargsCollector(Block[].class).asType(methodType(Block.class, javaArgumentTypes));
  return new ScalarFunctionImplementation(false, argumentProperties, methodHandle, isDeterministic());
}

代码示例来源:origin: com.headius/invokebinder

public MethodHandle up(MethodHandle target) {
  return target.asVarargsCollector(arrayType).asType(source);
}

代码示例来源:origin: io.prestosql/presto-main

@Override
public ScalarFunctionImplementation specialize(BoundVariables boundVariables, int arity, TypeManager typeManager, FunctionRegistry functionRegistry)
{
  List<Type> types = this.typeParameters.stream().map(boundVariables::getTypeVariable).collect(toImmutableList());
  List<ArgumentProperty> argumentProperties = nCopies(types.size(), valueTypeArgumentProperty(RETURN_NULL_ON_NULL));
  List<Class<?>> javaArgumentTypes = nCopies(types.size(), Block.class);
  MethodHandle methodHandle = METHOD_HANDLE.bindTo(types).asVarargsCollector(Block[].class).asType(methodType(Block.class, javaArgumentTypes));
  return new ScalarFunctionImplementation(false, argumentProperties, methodHandle, isDeterministic());
}

代码示例来源:origin: eclipse/golo-lang

public FunctionReference asVarargsCollector(Class<?> arrayType) {
 if (this.isVarargsCollector()) {
  return this;
 }
 return new FunctionReference(handle.asVarargsCollector(arrayType), this.parameterNames);
}

代码示例来源:origin: prestosql/presto

@Override
public ScalarFunctionImplementation specialize(BoundVariables boundVariables, int arity, TypeManager typeManager, FunctionRegistry functionRegistry)
{
  List<Type> types = this.typeParameters.stream().map(boundVariables::getTypeVariable).collect(toImmutableList());
  List<ArgumentProperty> argumentProperties = nCopies(types.size(), valueTypeArgumentProperty(RETURN_NULL_ON_NULL));
  List<Class<?>> javaArgumentTypes = nCopies(types.size(), Block.class);
  MethodHandle methodHandle = METHOD_HANDLE.bindTo(types).asVarargsCollector(Block[].class).asType(methodType(Block.class, javaArgumentTypes));
  return new ScalarFunctionImplementation(false, argumentProperties, methodHandle, isDeterministic());
}

代码示例来源:origin: eclipse/golo-lang

/**
 * Creates a function suitable for the {@code fallback} property delegating to the given dynamic object.
 *
 * Example:
 * <pre class="listing"><code class="lang-golo" data-lang="golo">
 * let d = DynamicObject(): name("Zaphod")
 * let o = DynamicObject(): fallback(delegate(d))
 * </code></pre>
 *
 * @param deleguee the object to delegate to.
 * @return a function delegating to {@code deleguee}
 */
public static FunctionReference delegate(DynamicObject deleguee) {
 return new FunctionReference(
   DISPATCH_DELEGATE.bindTo(deleguee).asVarargsCollector(Object[].class), //.asType(genericMethodType(2, true)),
   new String[]{"this", "name", "args"});
}

代码示例来源:origin: beanshell/beanshell

/** Appends varargs collector as appropriate to the MethodHandles lookup.
 * The return pushes the cascade chaining result to the parent.
 * {@inheritDoc} */
@Override
protected MethodHandle lookup(MethodHandle m) {
  if (isVarArgs() && null != m)
    return m.asFixedArity().asVarargsCollector(getVarArgsType());
  return m;
}

代码示例来源:origin: org.jsimpledb/jsimpledb-parse

@Override
public <T> Node resolve(ParseSession session, TypeToken<T> type) {
  // Get lookup
  final MethodHandles.Lookup lookup = MethodHandles.lookup();
  // Get handle to this.invoke()
  final MethodType invokeMethodType = MethodType.methodType(Object.class, ParseSession.class, Object[].class);
  final MethodHandle invokeHandle;
  try {
    invokeHandle = lookup.findVirtual(LambdaNode.class, "invoke", invokeMethodType).bindTo(this);
  } catch (IllegalAccessException | NoSuchMethodException e) {
    throw new RuntimeException("internal error", e);
  }
  // Insert ParseSession as first parameter
  final MethodHandle invokeHandleWithSession = MethodHandles.insertArguments(invokeHandle, 0, session);
  // Enable varargs collection
  final MethodHandle invokeHandleWithSessionAndVarargs = invokeHandleWithSession.asVarargsCollector(Object[].class);
  // Create proxy
  final Object proxy = MethodHandleProxies.asInterfaceInstance(type.getRawType(), invokeHandleWithSessionAndVarargs);
  // Return node containing proxy
  return new ConstNode(new ConstValue(proxy));
}

代码示例来源:origin: io.permazen/permazen-parse

@Override
public <T> Node resolve(ParseSession session, TypeToken<T> type) {
  // Get lookup
  final MethodHandles.Lookup lookup = MethodHandles.lookup();
  // Get handle to this.invoke()
  final MethodType invokeMethodType = MethodType.methodType(Object.class, ParseSession.class, Object[].class);
  final MethodHandle invokeHandle;
  try {
    invokeHandle = lookup.findVirtual(LambdaNode.class, "invoke", invokeMethodType).bindTo(this);
  } catch (IllegalAccessException | NoSuchMethodException e) {
    throw new RuntimeException("internal error", e);
  }
  // Insert ParseSession as first parameter
  final MethodHandle invokeHandleWithSession = MethodHandles.insertArguments(invokeHandle, 0, session);
  // Enable varargs collection
  final MethodHandle invokeHandleWithSessionAndVarargs = invokeHandleWithSession.asVarargsCollector(Object[].class);
  // Create proxy
  final Object proxy = MethodHandleProxies.asInterfaceInstance(type.getRawType(), invokeHandleWithSessionAndVarargs);
  // Return node containing proxy
  return new ConstNode(new ConstValue(proxy));
}

代码示例来源:origin: eclipse/golo-lang

public FunctionReference bindTo(Object x) {
 MethodHandle mh = this.handle.bindTo(x);
 if (isVarargsCollector() && arity() > 1) {
  mh = mh.asVarargsCollector(Object[].class);
 }
 return new FunctionReference(mh, dropParameterNames(0, 1));
}

代码示例来源:origin: eclipse/golo-lang

/**
 * Partial application.
 *
 * @param position the argument position (0-indexed).
 * @param value the argument value.
 * @return a partially applied function.
 */
public FunctionReference bindAt(int position, Object value) {
 MethodHandle mh = MethodHandles.insertArguments(this.handle, position, value);
 if (isVarargsCollector() && position < arity() - 1) {
  mh = mh.asVarargsCollector(Object[].class);
 }
 return new FunctionReference(mh, dropParameterNames(position, 1));
}

代码示例来源:origin: org.dynalang/dynalink

private static MethodHandle dropReceiver(final MethodHandle mh, final Class<?> receiverClass) {
    MethodHandle newHandle = MethodHandles.dropArguments(mh, 0, receiverClass);
    // NOTE: this is a workaround for the fact that dropArguments doesn't preserve vararg collector state.
    if(mh.isVarargsCollector() && !newHandle.isVarargsCollector()) {
      final MethodType type = mh.type();
      newHandle = newHandle.asVarargsCollector(type.parameterType(type.parameterCount() - 1));
    }
    return newHandle;
  }
}

代码示例来源:origin: eclipse/golo-lang

/**
 * Partial application.
 *
 * @param position the first argument position.
 * @param values the values of the arguments from {@code position}.
 * @return a partially applied function.
 * @see java.lang.invoke.MethodHandles#insertArguments(MethodHandle, int, Object...)
 */
public FunctionReference insertArguments(int position, Object... values) {
 if (values.length == 0) {
  return this;
 }
 MethodHandle mh = MethodHandles.insertArguments(this.handle, position, values);
 if (isVarargsCollector() && position < arity() - 1) {
  mh = mh.asVarargsCollector(Object[].class);
 }
 return new FunctionReference(mh, dropParameterNames(position, values.length));
}

代码示例来源:origin: szegedi/dynalink

private static MethodHandle dropReceiver(final MethodHandle mh, final Class<?> receiverClass) {
    MethodHandle newHandle = MethodHandles.dropArguments(mh, 0, receiverClass);
    // NOTE: this is a workaround for the fact that dropArguments doesn't preserve vararg collector state.
    if(mh.isVarargsCollector() && !newHandle.isVarargsCollector()) {
      final MethodType type = mh.type();
      newHandle = newHandle.asVarargsCollector(type.parameterType(type.parameterCount() - 1));
    }
    return newHandle;
  }
}

代码示例来源:origin: eclipse/golo-lang

public static MethodHandle getDecoratedMethodHandle(Lookup caller, Method originalMethod, int arity) {
 try {
  Method decoratorMethod = getDecoratorMethod(originalMethod);
  MethodHandle decorator = caller.unreflect(decoratorMethod);
  decorator = MethodHandles.filterReturnValue(decorator, FUNCTION_REFERENCE_TO_METHODHANDLE);
  MethodHandle original = caller.unreflect(originalMethod);
  decorator = decorator.bindTo(new gololang.FunctionReference(original)).asType(methodType(MethodHandle.class));
  if (arity < 0) {
   MethodHandle combined = MethodHandles.foldArguments(INVOKE_WITH_ARGUMENTS, decorator);
   return combined.asVarargsCollector(Object[].class);
  } else {
   MethodHandle invoker = MethodHandles.invoker(MethodType.genericMethodType(arity));
   return MethodHandles.foldArguments(invoker, decorator);
  }
 } catch (IllegalAccessException ex) {
  throw new IllegalStateException("Unable to get the decorator for a method marked as decorated", ex);
 }
}

代码示例来源:origin: eclipse/golo-lang

if (superTarget.isVarargsCollector()) {
 superTarget = superTarget.asType(genericMethodType(superTarget.type().parameterCount() - 1, true))
  .asVarargsCollector(Object[].class);
} else {
 superTarget = superTarget.asType(genericMethodType(superTarget.type().parameterCount()));

代码示例来源:origin: anba/es6draft

private static MethodHandle adaptNativeMethodHandle(MethodHandle mh) {
    MethodType type = mh.type();
    boolean varargs = mh.isVarargsCollector();
    // Allow to omit execution context argument.
    if (type.parameterCount() == 0 || !type.parameterType(0).equals(ExecutionContext.class)) {
      mh = MethodHandles.dropArguments(mh, 0, ExecutionContext.class);
    }
    // Allow void return type.
    if (type.returnType() == void.class) {
      mh = MethodHandles.filterReturnValue(mh, MethodHandles.constant(Object.class, UNDEFINED));
    }
    // Restore var-args flag.
    if (varargs && !mh.isVarargsCollector()) {
      mh = mh.asVarargsCollector(mh.type().parameterType(mh.type().parameterCount() - 1));
    }
    return mh;
  }
}

代码示例来源:origin: szegedi/dynalink

return isVarArg && !returnFiltered.isVarargsCollector() ? returnFiltered.asVarargsCollector(type.parameterType(paramCount - 1)) : returnFiltered;

代码示例来源:origin: org.dynalang/dynalink

return createConvertingInvocation(target, linkerServices, callSiteType).asVarargsCollector(
    callSiteLastArgType);

代码示例来源:origin: eclipse/golo-lang

other.asType(other.type().changeParameterType(0, Object.class)));
if (isVarargsCollector()) {
 mh = mh.asVarargsCollector(Object[].class);

相关文章