2015-06-18 48 views
7

我收到以下错误:为什么此方法调用失败? (泛型和通配符)

'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或子类,我正在传递一个子类)。任何帮助(+解释)将不胜感激!

谢谢!

回答

6

您的handler变量的类型参数通配符。编译器不知道该类型参数的确切类型,只是它是Monitor或子类。

call方法需要一个T,它在通配符上匹配。但是不能保证通配符类型是ContainsMonitor。它可能是Monitor,或者它可能是MonitorSubtypeThatDoesntExistYet。因为编译器不知道实际的类型,所以它不允许你传递除null以外的任何内容,因为对于任何非参数,它不能保证类型安全。

您可以通过删除通配符来解决此问题,并使用Monitor类中的类型参数替换该概念。

class Monitor<T extends Monitor<T>> 
{ 
    WebScoutCallable<T> handler; 

    public void setCallable(WebScoutCallable<T> callable) { 
     this.handler = callable; 
    } 
} 

接口WebScoutCallable变化不大响应:扩展Monitor

interface WebScoutCallable<T extends Monitor<T>> { 
    public void call(T caller); 
} 

子类饲料自己的名字作为类型参数。

class ContainsMonitor extends Monitor<ContainsMonitor> { 
    public void handleDocument() { 
      handler.call(this); 
    } 
} 

现在,T将是一个已知的类型,ContainsMonitor定义它是本身,因此它现在的法律为它本身传递给call

+0

感谢您的详细回复。我认为可能有一个不太详细的解决方案,但这是有道理的! – RNGuy

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); 
    } 
} 
+0

感谢您的快速响应。希望我能将两种解决方案标记为正确! – RNGuy

-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); 
    } 
} 
+3

这不回答OP的问题 –