Java 消费者<&燃气轮机;和消费者<;T>;似乎不完全等效-与任何消费功能接口相同
我有一个我不理解的java编译器错误。似乎消费者<?>和ConsumerJava 消费者<&燃气轮机;和消费者<;T>;似乎不完全等效-与任何消费功能接口相同,java,generics,method-reference,functional-interface,Java,Generics,Method Reference,Functional Interface,我有一个我不理解的java编译器错误。似乎消费者和Consumer(与T extends对象)在方法签名参数中不等价。请查看以下代码: import java.util.function.Consumer; public class MyClass { public void joker(Consumer<?> fct) {} public <T> void generic(Consumer<T> fct) {} public vo
import java.util.function.Consumer;
public class MyClass {
public void joker(Consumer<?> fct) {}
public <T> void generic(Consumer<T> fct) {}
public void myConsumer(String s) {}
public void doesNotCompile()
{
joker(this::myConsumer); // COMPILE ERROR : (In Eclipse : ) The type MyClass does not define myConsumer(Object) that is applicable here
generic(this::myConsumer); // Works fine : how come are "T" and "?" not equivalent here ?
// The following also works fine as usual :
Consumer<String> cs = this::myConsumer;
joker(cs);
joker((String s) -> myConsumer(s));
}
}
import java.util.function.Consumer;
公共类MyClass{
公共无效小丑(消费者fct){}
公共无效通用(消费者fct){}
公共空myConsumer(字符串s){}
public void不可编译()
{
joker(this::myConsumer);//编译错误:(在Eclipse:)类型MyClass没有定义适用于此处的myConsumer(Object)
泛型(this::myConsumer);//很好用:为什么“T”和“?”在这里不相等?
//以下功能也可以正常工作:
消费者cs=此::消费者;
小丑(cs),;
小丑((字符串s)->消费者(s));
}
}
当我通过命令行而不是在Eclipse中编译代码时,错误有点不同:
D:\>javac -Xdiags:verbose MyClass.java
MyClass.java:11: error: method joker in class MyClass cannot be applied to given types;
joker(this::myConsumer);
^
required: Consumer<?>
found: this::myConsumer
reason: argument mismatch; invalid method reference
method myConsumer in class MyClass cannot be applied to given types
required: String
found: Object
reason: argument mismatch; Object cannot be converted to String
1 error
D:\>javac-Xdiags:verbose MyClass.java
java:11:错误:MyClass类中的方法joker无法应用于给定类型;
小丑(这个::消费者);
^
必需:消费者
找到:this::myConsumer
原因:参数不匹配;无效的方法引用
类MyClass中的方法myConsumer无法应用于给定类型
必需:字符串
发现:对象
原因:参数不匹配;对象无法转换为字符串
1错误
这稍微清楚一点,但我还是不明白重点。注意:java.util.function.function出现模拟错误,但java.util.function.Supplier没有。因此,我相信任何函数接口都会出现错误
这是一个编译器错误还是我遗漏了什么?对于后者(最有可能),有人能说出这种行为设计的原因吗
我觉得类型推断出了问题。我也几乎不知道JVM以不同的方式处理lambda和方法引用(AFAIK通过MethodHandler)。但老实说,我只是感到困惑
帮忙?¯\ (ツ)/“”
TL;DR;编译器实际上禁止将null
以外的任何值传递给使用者
。因此使用者
的用法实际上是零
用你的小丑
方法试试这个:
fct.accept(new Object());
您将看到它不会编译,因为编译器无法确保传递的使用者
确实可以接受对象
s。但是使用null
有效,因为它是所有对象
的唯一有效值:
fct.accept(null);
您可以通过使用未经检查的强制类型转换来克服此限制,但它们实际上是不受鼓励的,因为您可能会遇到ClassCastException
请记住,Consumer
不等于Consumer
。前者允许向其传递任何对象,而后者不接受任何内容!(当然null
除外)
您的另一个“很好”的示例:
但在幕后,你也在使用未经检查的强制转换。你在隐式地将s
从Object
转换为String
。这几乎等同于编写:
joker(s -> myConsumer((String) s));
甚至是这样(因为s
只知道是对象
):
对于您的另一个问题,为什么T
和不一样。T
是泛型类型,编译器试图将其缩小到最具体的类型。对于泛型(this::myConsumer)
,T
将是字符串
,如果编译器无法推断类型,它将只使用对象
,因此它类似于消费者
,但不是消费者
总而言之,使用消费者
可能永远不会有一个真正的用例,因为如果没有任何恶意的黑客攻击,你只能将null
传递给它。这有什么用呢?小丑(这个::我的消费者);
在强制目标类型为消费者的上下文中使用方法引用this::myConsumer
,其中编译器被迫为?
使用对象
。鉴于此,需要有myConsumer
的签名,而MyC中没有签名lass
为什么“T”和“?”在这里不相等
这不是问题所在。请参阅以下编译代码:
Consumer<String> jokerConsumer = this::myConsumer;
joker(jokerConsumer);
Consumer jokerConsumer=this::myConsumer;
小丑(小丑消费者);
唯一的区别是方法引用(及其目标类型)在MyClass
中有一个兼容的方法
此外,如果将public void myConsumer(Object s){}
添加到类中,则原始的joker(this::myConsumer);
编译得很好
通用方法之所以有效,是因为T
被推断为与myConsumer
的参数类型相同,从而结束了问题
这说明了解决当前问题的两种方法。简而言之,这是一个方法引用的目标类型问题(在方法调用的上下文中)与引用方法的签名兼容。此::myConsumer
被视为消费者
消费者=此::myConsumer;
不起作用
joker((Object s) -> myConsumer((String) s));
Consumer<String> jokerConsumer = this::myConsumer;
joker(jokerConsumer);