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
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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With