我收到以下错误:
'call(ContainsMonitor)' cannot invoke 'call(? extends webscout.Monitor)' in 'WebScoutCallable'
Monitor.java
WebScoutCallable<? extends Monitor> handler;
public setCallable(WebScoutCallable<? extends Monitor> callable) {
this.handler = callable;
}
WebScoutCallable.java
public interface WebScoutCallable<T extends Monitor> {
public void call(T caller);
}
ContainsMonitor.java
public class ContainsMonitor extends Monitor {
public void handleDocument() {
handler.call(this);
}
}
我会自由地承认,我是仿制药的新手,对Java本身来说还是一个新手。我发现错误消息令人困惑,因为它看起来应该工作(方法声明需要一个Monitor或子类,我传入一个子类)。任何帮助(+解释)将不胜感激!
谢谢!
答案 0 :(得分:6)
您的handler
变量的type参数中有一个通配符。编译器不知道这个类型参数的确切类型是什么,只是它是Monitor
或子类。
call
方法采用T
,在通配符上匹配。但是不能保证通配符类型是ContainsMonitor
。它可以是Monitor
,也可以是MonitorSubtypeThatDoesntExistYet
。因为编译器不知道实际类型,所以它不允许您传递除null
之外的任何内容,因为任何非null
参数都不能保证类型安全。
您可以通过删除通配符并使用Monitor
类上的类型参数替换该概念来解决此问题。
class Monitor<T extends Monitor<T>>
{
WebScoutCallable<T> handler;
public void setCallable(WebScoutCallable<T> callable) {
this.handler = callable;
}
}
接口WebScoutCallable
稍有改动:
interface WebScoutCallable<T extends Monitor<T>> {
public void call(T caller);
}
在扩展Monitor
时,子类将自己的名称作为类型参数提供。
class ContainsMonitor extends Monitor<ContainsMonitor> {
public void handleDocument() {
handler.call(this);
}
}
现在,T
将是一种已知类型,ContainsMonitor
将其定义为自身类型,因此现在将其自身传递给call
是合法的。
答案 1 :(得分:3)
? extends Monitor
表示:Monitor的特定子类,但我们不知道哪一个。因此,它可能是ContainsMonitor
,而handler
可能会或可能无法接受ContainsMonitor
。编译器无法决定并显示错误。
解决问题的一种方法是使用特定类型,例如:
class Monitor<T extends Monitor<T>> {
WebScoutCallable<T> handler;
public setCallable(WebScoutCallable<T> callable) {
this.handler = callable;
}
}
class ContainsMonitor extends Monitor<ContainsMonitor> {
public void handleDocument() {
handler.call(this);
}
}
答案 2 :(得分:-5)
您的代码不需要泛型。
public class Monitor {
WebScoutCallable handler;
public void setCallable(WebScoutCallable callable) {
this.handler = callable;
}
}
public interface WebScoutCallable {
public void call(Monitor caller);
}
public class ContainsMonitor extends Monitor {
public void handleDocument() {
handler.call(this);
}
}