传入泛型方法参数时出现Java错误

问题描述 投票:0回答:1
public static class MyClass {
    public String methodS(UnaryOperator<String> fn) {
        return fn.apply("");
    }
    public Integer methodI(UnaryOperator<Integer> fn) {
        return fn.apply(0);
    }
    public <T> T identity(T t) {
        return t;
    }
    public <T> void test(UnaryOperator<T> fn) {
        String s;
        s = methodS(UnaryOperator.identity()); // OK
        s = methodS(this::identity);           // OK
        s = methodS(String::trim);             // OK
        s = methodS(fn::apply);                // Fail
        Integer i;
        i = methodI(UnaryOperator.identity()); // OK
        i = methodI(this::identity);           // OK
        i = methodI(Math::abs);                // OK
        i = methodI(fn::apply);                // Fail
    }
    public void goal() {
        test(o -> {
            doSomething(o);
            return o;
        });
    }
}

我想知道为什么在上面的示例中传递类方法引用可以,但传递方法参数却不行?怎么解决呢?

目标是能够像

goal()
方法一样进行调用,其中可以编写通用 lambda 来接受公共基类对象(在本例中为
Object
)。


编辑:有些人误解了这个问题,可能是因为

Object
作为基类。这里可能是一个更好的例子,其中包含一些自定义的公共基类:

public static class MyClass {
    public static class ExtS extends MyClass {};
    public static class ExtI extends MyClass {};
    public void common() {}
    public ExtS methodS(UnaryOperator<ExtS> fn) {
        return fn.apply(new ExtS());
    }
    public ExtI methodI(UnaryOperator<ExtI> fn) {
        return fn.apply(new ExtI());
    }
    public <X extends MyClass> X identity(X x) {
        x.common(); // can call MyClass methods
        return x;
    }
    public <Y extends MyClass> void test(UnaryOperator<Y> fn) {
        ExtS s;
        s = methodS(UnaryOperator.identity());    // OK
        s = methodS(this::identity);              // OK
        s = methodS(t -> (ExtS) fn.apply((Y) t)); // OK
        s = methodS(fn::apply);                   // fail
        ExtI i;
        i = methodI(UnaryOperator.identity());    // OK
        i = methodI(this::identity);              // OK
        i = methodI(t -> (ExtI) fn.apply((Y) t)); // OK
        i = methodI(fn::apply);                   // fail
    }
    public void goal() {
        test(y -> {
            y.common(); // can call MyClass methods
            return y;
        });
        test(this::identity); // doing the same as above
    }
}
java generics lambda method-reference
1个回答
0
投票

你应该退后一步,尝试做实际的作业。当您尝试执行

methodI
时,您所做的就是将参数分配给
UnaryOperator<ExI>

static <T> UnaryOperator<T> identity()

这意味着T是在调用identity时分配的。

methodI(UnaryOperator::identity);

这很好,这就是恒等式的要点,你用一个参数来调用它,它就会采用那个通用的。当您调用

methodI
时,它会将 UnaryOperator.identity 的泛型指定为
ExtI

methodI(this::identity);

与前面的示例相同,当您调用identity时,它会获取类型,因此只有在methodI的参数中分配它时,类型才会定义。

methodI(fn::apply);

这不好,因为你已经分配了 fn 的类型。它是

Y
,关于
Y
,你所知道的就是它是一个
MyClass
,而且是它的父母。这意味着 methodI 正在尝试分配。
UnaryOperatory<ExtI> fn
UnaryOperator<? extends MyClass>
。它们不是同一件事。但他们可能是。这就是为什么

methodI(t -> (ExtI) fn.apply((Y) t));

有效。你的约束并不能说明你所做的事情是错误的,它们只是不能保证正确性。如果您使用显式强制转换,您可以“使其工作”。

© www.soinside.com 2019 - 2024. All rights reserved.