作为与Holgers' solution密切相关的后续问题,为什么取消注释覆盖会破坏下面的工作代码?
public static interface StringFunction<N extends Number> extends Function<String, N> {
// @Override
// N apply(String t);
}
仅当上述评论未被删除时,此方法才有效:
public static <N extends Number> StringFunction<N> create(Class<N> type) throws Throwable {
MethodType methodType = MethodType.methodType(type, String.class);
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle handle = lookup.findConstructor(type,
MethodType.methodType(void.class, String.class));
StringFunction<N> f = (StringFunction<N>) LambdaMetafactory.metafactory(lookup, "apply",
MethodType.methodType(StringFunction.class),
methodType.generic(), handle, methodType).getTarget().invokeExact();
return f;
}
public static void main(String[] args) throws Throwable {
System.out.println(create(Byte.class).apply("1"));
System.out.println(create(Short.class).apply("2"));
System.out.println(create(Integer.class).apply("3"));
System.out.println(create(Long.class).apply("4"));
}
运行时抱怨:
Exception in thread "main" java.lang.AbstractMethodError:
Method LambdaFun$$Lambda$1.apply(Ljava/lang/String;)Ljava/lang/Number; is abstract
at LambdaFun$$Lambda$1/856419764.apply(Unknown Source)
at LambdaFun.main(LambdaFun.java:28)
答案 0 :(得分:4)
在使用带有metafactory的通用interface
时,您需要了解Generics如何在字节码级别上工作。
声明{/ 1}}方法时
interface
原始类型public static interface StringFunction<N extends Number> extends Function<String, N> {
@Override
N apply(String t);
}
将有一个必须实现StringFunction
签名的方法。它还包含一个编译器生成的桥接方法,它覆盖了将委托给Number apply(String)
方法的继承方法Object apply(Object)
(这是一件好事,例如当abstract
在Java下编译时7或更早,我们必须使用altMetafactory
明确声明所有必需的桥接方法,比较«this answer»)。
因此您必须将工厂方法更改为:
interface
让它发挥作用。请注意,我们现在保留现在已修复的public static <N extends Number> StringFunction<N> create(Class<N> type) throws Throwable {
MethodType methodType = MethodType.methodType(type, String.class);
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle handle = lookup.findConstructor(type,
MethodType.methodType(void.class, String.class));
StringFunction<N> f = (StringFunction<N>) LambdaMetafactory.metafactory(lookup, "apply",
MethodType.methodType(StringFunction.class),
methodType.changeReturnType(Number.class), handle, methodType).getTarget().invokeExact();
return f;
}
参数类型,并仅使用String
将返回类型更改为其下限。
此外,请注意此代码如何隐藏有关泛型的错误。您在应该由参数methodType.changeReturnType(Number.class)
替换的位置使用Integer.class
,但它不会立即中断,因为您的示例代码从不尝试分配此类函数返回的值,例如type
到该类型的变量,因此您没有注意到StringFunction<Short>
返回StringFunction<Short>
。我在我的示例代码中修复了这个问题,例如Integer
确实返回StringFunction<Short>
。