gpt4 book ai didi

java - "incompatible types"lambda/方法引用和泛型编译器错误

转载 作者:搜寻专家 更新时间:2023-11-01 03:35:51 26 4
gpt4 key购买 nike

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

我的示例包括...

  1. 一个功能接口(interface),GenericListener,它接受一个类型参数 V 并且有一个方法“genericCallback(V genericValue)”。

  2. 一个类,CallbackProducer,它带有一个类型参数 T。这个类还有一个方法来添加一个 Integer 类型的 GenericListener。

  3. Main 类,它创建 CallbackProducers 并向其添加 GenericListeners。

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

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

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

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

这种行为有原因吗?我是不是误会了什么,或者这是 java 编译器中的弱点或错误? (我目前使用的是java 1.8_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);
}
}

最佳答案

所有 3 个编译器错误都是由于您使用的是原始 CallbackProducer。 .当您使用原始 CallbackProducer ,所有类型参数都经过类型删除,这样任何 T ,比如你的,没有任何上限,变成 Object .

因此,addIntegerListener方法需要原始 GenericListener作为参数,integerReceived不再适合。 integerReceived方法采用 Integer ,不是 Object , 作为原始 GenericListener会供应。

您必须提供尖括号 <>CallbackProducer避免使用原始类型,正如您在后续示例中所做的那样。

关于java - "incompatible types"lambda/方法引用和泛型编译器错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31840158/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com