当实例作为其超接口(interface)传递时,Java 8 默认实现不可用

标签 java java-8

我在调用一个我认为应该在目标实例中具有默认实现的方法时收到一个AbstractMethodError

我在三个参数中创建了一个功能接口(interface),但也派生自 java.util.function.Function 并提供了 Function#apply(..) 的默认实现。然后,我使用 3 参数 lambda 表达式创建了我的接口(interface)实例。 3 参数方法和 Function#apply(..) 在创建的实例中工作得很好。

当我将创建的实例传递给需要我的接口(interface)的方法时,我可以从该方法中调用 Function#apply(..),它工作正常。

但是,当我将实例传递给需要 Function 的方法时,当我尝试调用 Function#apply(.. )

我似乎缺少对默认方法如何以及何时绑定(bind)到实例的理解。我做错了什么?

演示:

package spike;

import java.util.function.BiFunction;
import java.util.function.Function;

public class ReductionProblem {

    interface F3<T, U, V, R> extends Function<T, BiFunction<U, V, R>> {

        default BiFunction<U, V, R> apply(final T t) {
            return (U u, V v) -> apply(t, u, v);
        }

        R apply(T t, U u, V v);

    }

    private static <T, U, V, R> BiFunction<U, V, R> workingReduce(
            F3<T, U, V, R> f, T t) {
        return f.apply(t);
    }

    private static <T, U, V, R> BiFunction<U, V, R> brokenReduce(
            Function<T, BiFunction<U, V, R>> f, T t) {
        return f.apply(t);
    }

    public static void main(String[] args) {

        /*
         * Object is instantiated here, right? So, Function#apply(Integer)
         * should be defined and ready to go.
         */
        final F3<Integer, Integer, String, Integer> f3 = (a, b, c) -> a * b
                * c.length();

        final Integer a = 3, b = 13;
        final String c = "see";

        final Integer expected = a * b * c.length();

        Integer v1 = f3.apply(a, b, c);
        display("invoke with 3", expected, v1);

        /*
         * It appears that f3 can indeed behave as a Function<Integer,
         * BiFunction<>> ...
         */
        Integer v2 = f3.apply(a).apply(b, c);
        display("invoke with 1 then 2", expected, v2);

        /*
         * From inside a method, no problem...
         */
        Integer v3 = workingReduce(f3, a).apply(b, c);
        display("invoke with 1 inside special reducer", expected, v3);

        /*
         * But when passed explicitly as a Function, AbstractMethodError is
         * thrown from inside the reduction method. So, it seems that the
         * instantiation of the object with the default method implementation
         * does not occur where I am supposing it does.
         */
        Integer v4 = brokenReduce(f3, a).apply(b, c);
        display("invoke with 1 inside general reducer", expected, v4);

    }

    private static void display(String label, Object expected, Object actual) {

        System.out.println(label + ":"
                + (actual.equals(expected) ? "pass" : "fail"));

    }

}

最佳答案

这似乎是您使用的任何编译器中的错误。我只能用 Eclipse 编译器重现它。它适用于

[~/workspace/Example/bin]$ javac -version
javac 1.8.0_05
[~/workspace/Example/bin]$ 

这里的错误似乎是编译器没有添加用于调用方法的invokeinterface,而是引用了抽象方法本身。或者它可能会在没有 default 方法实现的情况下构建由 lambda 生成的实例,但这似乎不太可能,因为其他调用有效。

关于当实例作为其超接口(interface)传递时,Java 8 默认实现不可用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24093631/

相关文章:

java - 并行流是否可以在不同的操作下正常工作?

java - 为什么这个简单的 SOAP 客户端不工作 (org.apache.http)?

java - 有没有可能知道一个HashSet中新增的符号?

java - Hybris 后台 : how to trigger a create wizard programmatically

Java:获取 lambda 的泛型类型

Java 8 流执行

java-8 - JavaFX : ObsevableMap keySet as an ObservableSet

java - 如何使用非固定值设置消息处理器间隔参数? (使用存储在 property\registry\etc 中的值)

java - 如何在 Java2D/Graphics2D 中指定后备字体

java - 在 spring-data 中为 MongoDB 配置 GridFS 模板