此帖终结,查看Groovy源码,找到其闭包调用过程,原理是其调用闭包前,先去闭包内按照参数类型查找闭包的call方法,如果参数和闭包的call参数匹配上,则通过反射调用闭包,否则判断参数长度为1且是List的情况下尝试将List内部数据取出,作为参数再查找闭包是否存在满足参数类型的方法。
org.codehaus.groovy.runtime.metaclass.ClosureMetaClass#invokeMethod
Object invokeMethod(Class sender, Object object, String methodName, Object[] originalArguments, boolean isCallToSuper, boolean fromInsideClass) {
//获取参数和参数的类型
final Object[] arguments = makeArguments(originalArguments, methodName);
final Class[] argClasses = MetaClassHelper.convertToTypeArray(arguments);
MetaMethod method = null;
final Closure closure = (Closure) object;
if (CLOSURE_DO_CALL_METHOD.equals(methodName) || CLOSURE_CALL_METHOD.equals(methodName)) {
//选择闭包的method,因为这里的参数类型不满足闭包的参数类型,所以这里返会null
method = pickClosureMethod(argClasses);
//判断参数只有一个且是List,则尝试将参数list内部数据取出,使用此类型从闭包中查找方法
if (method == null && arguments.length == 1 && arguments[0] instanceof List) {
Object[] newArguments = ((List) arguments[0]).toArray();
Class[] newArgClasses = MetaClassHelper.convertToTypeArray(newArguments);
//这里参数类型匹配成功,将查找到的method使用TransformMetaMethod包装起来
method = createTransformMetaMethod(pickClosureMethod(newArgClasses));
}
//这里将method包装起来,重写invoke方法,因为确定参数是List了,将其内部数据取出组成数组调用真实method
protected MetaMethod createTransformMetaMethod(MetaMethod method) {
if (method == null) {
return null;
}
return new TransformMetaMethod(method) {
public Object invoke(Object object, Object[] arguments) {
Object firstArgument = arguments[0];
List list = (List) firstArgument;
arguments = list.toArray();
return super.invoke(object, arguments);
}
};
}
这应该是闭包的特殊逻辑,其他正常方法是没有这种逻辑的,如果想要将List展平作为参数,仍需使用星号的形式。