当前位置: 首页 > 知识库问答 >
问题:

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

史超英
2023-03-14

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

我的示例包括。。。

>

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

    一个类,CallbackProducer,它采用类型参数T。此类还有一个方法可以添加类型为Integer的GenericListener。

    一个Main类,它创建CallbackProducers并将GenericListeners添加到它们中。

    当我从Main的构造函数运行CallbackProducer的addIntgerListener方法时,每当我避免指定CallbackProducer的T类型时,我都会收到编译器错误:“不兼容类型”。

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

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

    此外,如果CallbackProducer不使用泛型,并且我们完全删除了类型参数T,则对addIntgerListener的3个第一次调用将编译。

    这种行为有什么原因吗?我是否误解了什么,或者这是java编译器中的一个弱点或错误?(我目前正在使用java 1.8\u 51)

    提前感谢您的澄清!

    import javax.swing.*;
    
    public class Main {
    
        public static void main(final String[] args) {
            SwingUtilities.invokeLater(Main::new);
        }
    
        public Main() {
    
            // Compiler error, type of CallbackProducer's "T" not specified
            CallbackProducer producer1 = new CallbackProducer();
            producer1.addIntegerListener(this::integerReceived);
    
            // Compiler error, no diamond brackets for CallbackProducer
            new CallbackProducer().addIntegerListener(this::integerReceived);
    
            // Also compiler error for lambdas with no diamond brackets on CallbackProducer
            new CallbackProducer().addIntegerListener(intValue -> integerReceived(intValue));
    
            // Works because a (any) type for CallbackProducer's "T" is specified
            CallbackProducer<Object> producer2 = new CallbackProducer<>();
            producer2.addIntegerListener(this::integerReceived);
    
            // Works because of the diamond brackets
            new CallbackProducer<>().addIntegerListener(this::integerReceived);
    
            // Lambda also works with diamond brackets
            new CallbackProducer<>().addIntegerListener(intValue -> integerReceived(intValue));
    
            // This variant also works without specifying CallbackProducer's "T"
            // ... but it is a workaround I'd prefer to avoid if possible :-P
            GenericListener<Integer> integerListener = this::integerReceived;
            new CallbackProducer().addIntegerListener(integerListener);
        }
    
        private void integerReceived(Integer intValue) {
            System.out.println("Integer callback received: " + intValue);
        }
    
        // A callback producer taking generic listeners
        // Has a type parameter "T" which is completely unrelated to
        // GenericListener's "V" and not used for anything in this
        // example really, except help provoking the compiler error
        public class CallbackProducer<T> {
            // Adds a listener which specifically takes an Integer type as argument
            public void addIntegerListener(GenericListener<Integer> integerListener) {
                // Just a dummy callback to receive some output
                integerListener.genericCallback(100);
            }
        }
    
        // A simple, generic listener interface that can take a value of any type
        // Has a type parameter "V" which is used to specify the value type of the callback
        // "V" is completely unrelated to CallbackProducer's "T"
        @FunctionalInterface
        public interface GenericListener<V> {
            void genericCallback(V genericValue);
        }
    }
    

    这是一个简短的版本,没有所有注释混乱,只调用了两个“addIntegerListener”,其中一个调用会导致编译器错误。

    import javax.swing.*;
    
    public class Main {
    
        public static void main(final String[] args) {
            SwingUtilities.invokeLater(Main::new);
        }
    
        public Main() {
    
            CallbackProducer producer1 = new CallbackProducer();
            producer1.addIntegerListener(this::integerReceived);    // Compiler error
    
            CallbackProducer<Object> producer2 = new CallbackProducer<>();
            producer2.addIntegerListener(this::integerReceived);    // Compiles OK      
        }
    
        private void integerReceived(Integer intValue) {
            System.out.println("Integer callback received: " + intValue);
        }
    
        public class CallbackProducer<T> {
            public void addIntegerListener(GenericListener<Integer> integerListener) {
                integerListener.genericCallback(100);
            }
        }
    
        @FunctionalInterface
        public interface GenericListener<V> {
            void genericCallback(V genericValue);
        }
    }
    
  • 共有1个答案

    武嘉祥
    2023-03-14

    所有3个编译器错误都是由于您使用的是原始CallbackProducer。当您使用原始的CallbackProducer时,所有类型参数都会经历类型擦除,这样,任何类型的参数(如您的)都会成为对象,而没有任何上限。

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

    您必须提供尖括号

     类似资料:
    • 问题内容: 我在写一些代码,遇到编译错误。这就是我所拥有的: 我以为使用继承时没有正确声明泛型,所以我检查了Oracle的教程,他们在其中编写 上面的声明使用相同的泛型类型,这是我在示例中要完成的工作。似乎假设from 与from 有所不同。否则,它应该能够 将 两者 合并并看到相同的类型。如何正确实现我要实现的目标? ( 即,某物的常量是某物的值,这是同一物的表达 ) 问题答案: 您的变量定义为

    • 在stackoverflow中还没有讨论的情况下,我遇到了“不兼容类型”编译器错误(例如,为什么这个通用java代码不能编译?)。 我的期望很简单--我调用的是一个模板化方法,它不使用包含类的任何“泛型”类,因此它应该从方法参数中提取模板参数的类型,并且在所有情况下都应该编译--但我得到了“不兼容类型”编译器错误。 我注意到解决这个问题的奇怪方法--在方法参数中向泛型datatype添加“<?ex

    • 我在抽象课上有以下内容... 还有另一个类,它继承了这个类... 当我从主类执行以下调用时,我收到一个错误... 我的问题是..为什么会发生这种情况?我的getEntityById不是返回T型的东西,在这种情况下应该是产品吗? 我在 Netbeans 中工作,编译时未显示任何错误。 感谢您的帮助=)

    • 我定义jackoson序列化器并将其添加到java类中,如下所示: 编译器出现以下错误: 注释的定义为: 如果我从ReportFilterDeserializer中删除泛型attibute,它将通过编译。我不明白编辑为什么抱怨。

    • 和是的一部分,如下所示:

    • 在下面的情况下,我在理解Java泛型的行为时遇到了问题。 具有一些参数化接口和一些类上的方法,这些类返回扩展该接口的类,由、1.8Oracle JDK、OSX和Linux生成java编译错误,但不是由Eclipse IDE中的Eclipse编译器生成的(它也可以在Eclipse RCP OSGi运行时下运行),实现如下: ./Gradlew build 最简单的修复是删除方法签名中泛型定义的一部分