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
}
}
你应该退后一步,尝试做实际的作业。当您尝试执行
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));
有效。你的约束并不能说明你所做的事情是错误的,它们只是不能保证正确性。如果您使用显式强制转换,您可以“使其工作”。