Java &引用;“不兼容类型”;lambda/方法引用和泛型的编译器错误

Java &引用;“不兼容类型”;lambda/方法引用和泛型的编译器错误,java,generics,lambda,compiler-errors,method-reference,Java,Generics,Lambda,Compiler Errors,Method Reference,在处理一些旧代码时,我偶然发现了一个问题,用lambda表达式或方法引用替换了几个匿名类。这个问题有点难以用语言来解释,但我会尽我最大的努力,下面我还添加了一个简短的例子,用我的最大能力来说明我的问题 我的例子包括 一个函数接口GenericListener,它接受一个类型参数V,并具有一个方法“genericCallback(V genericValue)” 一个类CallbackProducer,它接受一个类型参数T。这个类还有一个方法可以添加一个类型为Integer的GenericList

在处理一些旧代码时,我偶然发现了一个问题,用lambda表达式或方法引用替换了几个匿名类。这个问题有点难以用语言来解释,但我会尽我最大的努力,下面我还添加了一个简短的例子,用我的最大能力来说明我的问题

我的例子包括

  • 一个函数接口GenericListener,它接受一个类型参数V,并具有一个方法“genericCallback(V genericValue)”

  • 一个类CallbackProducer,它接受一个类型参数T。这个类还有一个方法可以添加一个类型为Integer的GenericListener

  • 一个Main类,它创建回调生产者并向其添加GenericListener

  • 当我从Main的构造函数运行CallbackProducer的addIntegerListener方法时,每当我避免指定CallbackProducer的T的类型时,就会出现编译器错误:“不兼容类型”

    addIntegerListener方法只使用GenericListener的V。据我所知,它没有以任何方式使用CallbackProducer的t

    我在Main的构造函数中多次调用addIntegerListener+注释,其中3个会导致编译器错误。但据我所知(根据IntelliJ),所有这些都应该是合法的。如果注释掉对addIntegerListener的前3个调用,应用程序将编译并运行良好

    另外,如果CallbackProducer没有使用泛型,并且我们完全删除了类型参数t,那么将编译对addIntegerListener的前3个调用

    这种行为有什么原因吗?是我误解了什么,还是这是java编译器中的一个弱点或错误?(我目前正在使用Java1.8_51)

    提前感谢您的任何澄清

    import javax.swing.*;
    公共班机{
    公共静态void main(最终字符串[]args){
    调用器(Main::new);
    }
    公用干管(){
    //编译器错误,未指定CallbackProducer的“T”类型
    CallbackProducer1=新的CallbackProducer();
    producer1.addIntegerListener(this::integerReceived);
    //编译器错误,CallbackProducer没有菱形括号
    新建CallbackProducer().addIntegerListener(this::integerReceived);
    //此外,CallbackProducer上没有菱形括号的lambdas的编译器错误
    新建CallbackProducer().addIntegerListener(intValue->integerReceived(intValue));
    //之所以有效,是因为为CallbackProducer的“T”指定了(任意)类型
    CallbackProducer2=新的CallbackProducer();
    producer2.addIntegerListener(this::integerReceived);
    //因为有菱形括号,所以可以正常工作
    新建CallbackProducer().addIntegerListener(this::integerReceived);
    //Lambda也适用于菱形括号
    新建CallbackProducer().addIntegerListener(intValue->integerReceived(intValue));
    //此变体也可以在不指定CallbackProducer的“T”的情况下工作
    //…但如果可能的话,这是一个我宁愿避免的解决方法:-P
    GenericListener integerListener=this::integerReceived;
    新建CallbackProducer().addIntegerListener(integerListener);
    }
    私有void integerReceived(Integer intValue){
    System.out.println(“接收到整数回调:“+intValue”);
    }
    //接受泛型侦听器的回调生产者
    //有一个类型参数“T”,它与
    //GenericListener的“V”,不用于本文档中的任何内容
    //这是一个真正的例子,除了有助于引发编译器错误之外
    公共类回调生成器{
    //添加一个侦听器,该侦听器专门接受整数类型作为参数
    public void addIntegerListener(GenericListener integerListener){
    //只是一个伪回调来接收一些输出
    integerListener.genericCallback(100);
    }
    }
    //一个简单的通用侦听器接口,可以接受任何类型的值
    //具有类型参数“V”,用于指定回调的值类型
    //“V”与CallbackProducer的“T”完全无关
    @功能接口
    公共接口GenericListener{
    作废genericCallback(V genericValue);
    }
    }
    
    这是一个简短的版本,没有所有的注释混乱,只调用了两个“addIntegerListener”,其中一个会导致编译器错误

    import javax.swing.*;
    公共班机{
    公共静态void main(最终字符串[]args){
    调用器(Main::new);
    }
    公用干管(){
    CallbackProducer1=新的CallbackProducer();
    producer1.addIntegerListener(this::integerReceived);//编译器错误
    CallbackProducer2=新的CallbackProducer();
    producer2.addIntegerListener(this::integerReceived);//编译正常
    }
    私有void integerReceived(Integer intValue){
    System.out.println(“接收到整数回调:“+intValue”);
    }
    公共类回调生成器{
    public void addIntegerListener(GenericListener integerListener){
    integerListener.genericCallback(100);
    }
    }
    @功能接口
    公共接口GenericListener{
    作废genericCallback(V genericValue);
    }
    }
    
    所有3个编译器错误都是由于您使用的是原始
    回调生产者。当您使用原始的
    CallbackProducer
    时,所有类型参数都会进行类型擦除,这样,任何
    T
    ,例如您的,没有任何上限,都会变成
    对象

    因此,
    addIntegerListener
    方法需要一个原始的
    GenericListener
    作为参数,
    integerReceived
    不再适用。
    integerReceived
    方法采用的是
    Integer
    ,而不是
    对象<