为什么这个方法调用失败? (泛型和通配符)
Why does this method call fail? (Generics & wildcards)
我收到以下错误:
'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);
}
包含Monitor.java
public class ContainsMonitor extends Monitor {
public void handleDocument() {
handler.call(this);
}
}
我承认我是泛型的新手,而且对 Java 本身还是很陌生。我发现错误消息令人困惑,因为它看起来应该有效(方法声明需要一个 Monitor 或子类,我正在传递一个子类)。任何帮助(+解释)将不胜感激!
谢谢!
? 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);
}
}
您的 handler
变量的类型参数中有一个通配符。编译器不知道这个类型参数的确切类型是什么,只知道它是 Monitor
或 subclass.
call
方法采用 T
,它在通配符上匹配。但是不能保证通配符类型是ContainsMonitor
。它可以是 Monitor
,也可以是 MonitorSubtypeThatDoesntExistYet
。因为编译器不知道实际类型,所以它不允许您传递除 null
之外的任何内容,因为对于任何非 null
参数,它都不能保证类型安全。
您可以通过删除通配符并在 Monitor
class.
上用类型参数替换该概念来解决此问题
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);
}
subclass 在扩展 Monitor
.
时将自己的名称作为类型参数
class ContainsMonitor extends Monitor<ContainsMonitor> {
public void handleDocument() {
handler.call(this);
}
}
现在,T
将是一个已知类型,而 ContainsMonitor
将其定义为自身,因此现在将其自身传递给 call
.[=28= 是合法的]
我收到以下错误:
'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);
}
包含Monitor.java
public class ContainsMonitor extends Monitor {
public void handleDocument() {
handler.call(this);
}
}
我承认我是泛型的新手,而且对 Java 本身还是很陌生。我发现错误消息令人困惑,因为它看起来应该有效(方法声明需要一个 Monitor 或子类,我正在传递一个子类)。任何帮助(+解释)将不胜感激!
谢谢!
? 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);
}
}
您的 handler
变量的类型参数中有一个通配符。编译器不知道这个类型参数的确切类型是什么,只知道它是 Monitor
或 subclass.
call
方法采用 T
,它在通配符上匹配。但是不能保证通配符类型是ContainsMonitor
。它可以是 Monitor
,也可以是 MonitorSubtypeThatDoesntExistYet
。因为编译器不知道实际类型,所以它不允许您传递除 null
之外的任何内容,因为对于任何非 null
参数,它都不能保证类型安全。
您可以通过删除通配符并在 Monitor
class.
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);
}
subclass 在扩展 Monitor
.
class ContainsMonitor extends Monitor<ContainsMonitor> {
public void handleDocument() {
handler.call(this);
}
}
现在,T
将是一个已知类型,而 ContainsMonitor
将其定义为自身,因此现在将其自身传递给 call
.[=28= 是合法的]