Why does this method call fail? (Generics & wildcards)

I am getting the below error:

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

I'll freely admit that I'm new to generics and still quite new to Java itself. I find the error message confusing as it looks like it should work (method declaration expects a Monitor or subclass, I'm passing in a subclass). Any help (+explanation) would be greatly appreciated!

Thanks!


You have a wildcard in the type parameter of your handler variable. The compiler doesn't know what the exact type of this type parameter is, only that it's either Monitor or a subclass.

The call method takes a T , which is matched on the wildcard. But there is no guarantee that the wildcard type is a ContainsMonitor . It could be a Monitor , or it could be MonitorSubtypeThatDoesntExistYet . Because the compiler doesn't know the actual type, it cannot allow you to pass anything except null , because with any non- null argument, it can't guarantee type safety.

You can get around this by removing the wildcard, and replacing that concept with a type parameter on the Monitor class.

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

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

The interface WebScoutCallable changes a little in response:

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

The subclass feeds its own name as the type argument when extending Monitor .

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

Now, T will be a known type, and ContainsMonitor defines it to be itself, so it's now legal for it to pass itself to call .


? extends Monitor ? extends Monitor means: a specific subclass of Monitor, but we don't know which one. So it may be a ContainsMonitor or not and handler may or may not be able to accept a ContainsMonitor . The compiler can't decide and shows an error.

One way to solve your problem is to use specific types, for example:

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

你的代码不需要泛型。

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);
     }
}
链接地址: http://www.djcxy.com/p/85840.html

上一篇: 使用Volley时出现SSL异常

下一篇: 为什么此方法调用失败? (泛型和通配符)