我在处理一些旧代码时偶然发现了一个问题,用lambda表达式或方法引用替换了几个匿名类。这个问题有点用文字来解释,但我会尽我所能,并且我还添加了一个简短的例子来说明我的问题,以下我的能力。
我的例子包括......
功能接口 GenericListener ,它采用类型参数V 并具有单个方法“genericCallback(V genericValue)”。
< / LI>一个类 CallbackProducer ,它采用类型参数T 。该类还有一个添加类型为Integer的GenericListener的方法。
一个 Main 类,它创建CallbackProducers并向其添加GenericListeners。
当我从Main的构造函数中运行CallbackProducer的addIntegerListener方法时,每当我避免指定CallbackProducer的T的类型时,我得到编译器错误:“不兼容的类型”。
方法addIntegerListener只使用GenericListener的V.据我所知,它不以任何方式使用CallbackProducer的T.
我在Main的构造函数中调用了几个addIntegerListener +注释,其中3个导致编译错误。但据我所知(并且根据IntelliJ),所有这些都应该是合法的。如果你注释掉第一次调用addIntegerListener,应用程序将编译并运行得很好。
此外,如果CallbackProducer没有使用泛型,并且我们完全删除了类型参数T,那么首先调用addIntegerListener将会编译。
这种行为有原因吗?我误解了什么,或者这是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);
}
}
答案 0 :(得分:1)
所有3个编译器错误都是由于您使用的是原始CallbackProducer
。当您使用原始CallbackProducer
时,所有类型参数都会进行类型擦除,这样任何T
(例如您的)都没有任何上限,变为Object
。
因此,addIntegerListener
方法需要原始GenericListener
作为参数,integerReceived
不再适合。 integerReceived
方法需要Integer
,而不是Object
,原始GenericListener
会提供。
您必须在<>
上提供尖括号CallbackProducer
,以避免使用原始类型,就像您在后续示例中所做的那样。