gpt4 book ai didi

java - LambdaMetafactory 的 AbstractMethodException

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:11:29 26 4
gpt4 key购买 nike

作为与 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)

最佳答案

使用通用时 interface对于元工厂,您需要了解泛型如何在字节码级别上工作。

声明 interface 时方法如

public static interface StringFunction<N extends Number> extends Function<String, N> {
@Override
N apply(String t);
}

原始类型 StringFunction将有一个签名为 Number apply(String) 的方法你必须实现。它还包含一个编译器生成的桥接方法,覆盖继承的方法 Object apply(Object)这将委托(delegate)给 abstract方法(否则这是一件好事,例如,当 interface 在 Java 7 或更早版本下编译时,我们必须使用 altMetafactory 显式声明所有必需的桥接方法,比较 «this answer» )。

因此您必须将工厂方法更改为:

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>真的返回一个Short .

关于java - LambdaMetafactory 的 AbstractMethodException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27426458/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com