I have this interface:
public interface Inflatable {
Pump<? extends Inflatable> getPump();
}
and this interface:
public Pump<T extends Inflatable> {
int readPressure(T thingToInflate);
}
Now this class:
public class Preparer {
public <T extends Inflatable> void inflate(T thingToInflate) {
int pressure = thingToInflate.getPump().readPressure(thingToInflate);
}
}
does not compile, with this error:
The method readPressure(capture#1-of ? extends Inflatable) in the type Pump is not applicable for the arguments (T)
What is wrong here? The variable thingToInflate
has to be an instance of a subclass of Inflatable
(because of <T extends Inflatable>
, right?), and the readPressure
method is defined to require a subclass of Inflatable
.
I know that this particular example is contrived, but the general case is that given an instance of T
, I can't then pass that instance to a method in another class that appears to define T
in exactly the same way. Can I fix this?
The Pump
returned by the getPump
might not be Pump<T>
. It returns Pump<U>
, where U
is something that extends Inflatable
. It's not safe to assume that T
is a subtype of U
.
Let's assume that there're 2 concrete classes that implement Inflatable
: C1
and C2
. getPump
may return an instance of Pump<C1>
. Let's assume that T
is C2
. An object of type C2
is not an instance of C1
, so it can't be passed to the readPressure
method.
That's why one can't "fix" it without a type safety violation.
Here's a concrete example showing that you're trying to do a wrong thing:
class C1 implements Inflatable, Pump<C1> {
@Override
public Pump<? extends Inflatable> getPump() {
return this; // an instance of C1 which implements Pump<C1>
}
@Override
public int readPressure(C1 thingToInflate) {
return 0;
}
}
class C2 implements Inflatable {
@Override
public Pump<? extends Inflatable> getPump() {
return new C1(); // again, an instance of C1 which implements Pump<C1>
}
}
public class Preparer {
public <T extends Inflatable> void inflate(T thingToInflate) {
int pressure = thingToInflate.getPump().readPressure(thingToInflate);
// Let's assume that it were possible. What happens if one calls
// new Preparer().inflate(new C2())?
// new C2().getPump() returns an instance of C1 which implements Pump<C1>
// It's readPressure method expects an instance of C1. But T = C2, so
// the thingToInflate is not an instance of C1.
// If the compiler allowed this to happen, the type safety
// would be violated.
}
}
The only thing you can do is redesigning your interfaces. I can't tell you an exact way to fix it because I don't know what your code is trying to accomplish in the first place.