Java 消费者<&燃气轮机;和消费者<;T>;似乎不完全等效-与任何消费功能接口相同

Java 消费者<&燃气轮机;和消费者<;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

我有一个我不理解的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 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);