为什么不能将泛型应用于相同的签名?

时间:2019-11-27 19:29:20

标签: java generics

我有以下代码片段,乍一看它应该可以工作,但是我收到一个非常有趣的错误:

'apply(capture<? extends Generic.MyClass>)' in 'java.util.function.Function' cannot be applied to '(capture<? extends Generic.MyClass>)'

此错误发生在这里:function.apply(wrapper.value);

我想念什么?

public class Generic {

    public static void main(String[] args) {
        Wrapper wrapper = new Wrapper<>(new MyClass());
    }

    private static void method(Wrapper<? extends MyClass> wrapper) {
        Function<? extends MyClass, String> function = (MyClass m) -> m.getClass().toString();
        function.apply(wrapper.value);
    }

    static class Wrapper<T extends MyClass> {
        private final T value;

        Wrapper(T value) {
            this.value = value;
        }
    }

    static class MyClass {

    }

}

2 个答案:

答案 0 :(得分:4)

将变量类型更改为(*):

Function<MyClass, String>

? extends MyClass表示此函数接受MyClass的特定子类,但是您只是不知道哪个子类。

尽管错误消息使它们看起来像是相同的类型,但事实并非如此:每个? extends MyClass都引用了不同的(但特定的)类型。

您唯一可以安全传递给此函数的内容是文字null

首字母缩略词PECS告诉您extends用于生产者方法(例如,“包装器产生价值”)。不适用于使用者方法(例如“函数接受T作为参数”):这就是super的用途。


(*)或仅使用wrapper.value.getClass().toString();,而不必费心声明函数。

答案 1 :(得分:0)

您可以使方法通用:

public class Main {

    public static void main(String[] args) {
        Wrapper wrapper = new Wrapper<>(new MyClass());
    }

    private static <T extends MyClass> void method(Wrapper<T> wrapper) {
        Function<T, String> function = (T m) -> m.getClass().toString();
        function.apply(wrapper.value);
    }

    static class Wrapper<T extends MyClass> {
        private final T value;

        Wrapper(T value) {
            this.value = value;
        }
    }

    static class MyClass {

    }

}