Java 为什么这个方法调用失败?(泛型和通配符)

Java 为什么这个方法调用失败?(泛型和通配符),java,generics,extends,Java,Generics,Extends,我得到以下错误: 'call(ContainsMonitor)' cannot invoke 'call(? extends webscout.Monitor)' in 'WebScoutCallable' Monitor.java WebScoutCallable<? extends Monitor> handler; public setCallable(WebScoutCallable<? extends Monitor> callable) { th

我得到以下错误:

'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;
}
public class ContainsMonitor extends Monitor {
     public void handleDocument() {
          handler.call(this);
     }
}
我可以坦率地承认,我是泛型新手,而且对Java本身还是相当陌生的。我发现错误消息令人困惑,因为它看起来应该可以工作(方法声明需要一个监视器或子类,我正在传递一个子类)。任何帮助(+解释)将不胜感激


谢谢

?扩展监视器
的意思是:监视器的一个特定子类,但我们不知道是哪个子类。因此,它可能是
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);
  }
}
类监视器{
WebScoutCallable处理器;
公共设置可调用(WebScoutCallable可调用){
this.handler=callable;
}
}
类ContainsMonitor扩展了监视器{
公共无效处理文件(){
handler.call(this);
}
}

处理程序的类型参数中有一个通配符。编译器不知道此类型参数的确切类型,只知道它是
Monitor
或子类

call
方法采用一个在通配符上匹配的
T
。但不能保证通配符类型是
ContainsMonitor
。它可以是
监视器
,也可以是
监视器子系统,但不属于纺织商
。因为编译器不知道实际的类型,所以它不能允许您传递除
null
之外的任何内容,因为对于任何非
null
参数,它不能保证类型安全

您可以通过删除通配符,并在
监视器
类中将该概念替换为类型参数来解决这个问题

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

    public void setCallable(WebScoutCallable<T> callable) {
         this.handler = callable;
    }
}
扩展
监视器时,子类将自己的名称作为类型参数提供

class ContainsMonitor extends Monitor<ContainsMonitor> {
     public void handleDocument() {
          handler.call(this);
     }
}
类ContainsMonitor扩展了监视器{
公共无效处理文件(){
handler.call(this);
}
}

现在,
T
将是一个已知的类型,
ContainsMonitor
将其定义为自身,因此现在将其自身传递给
call
是合法的。您的代码不需要泛型

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

这并没有回答OP的问题谢谢你的详细回答。我认为可能会有一个不那么冗长的解决方案,但这是有道理的!谢谢你的快速回复。但愿我能将两种解决方案标记为正确!
class ContainsMonitor extends Monitor<ContainsMonitor> {
     public void handleDocument() {
          handler.call(this);
     }
}
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);
     }
}