I have a class with strict, simple generic type:
public class GenericTools<T> {
private final Supplier<T> supplier;
private final Consumer<T> consumer;
public GenericTools(Supplier<T> supplier, Consumer<T> consumer) {
this.supplier = supplier;
this.consumer = consumer;
}
public Supplier<T> getSupplier() {
return supplier;
}
public Consumer<T> getConsumer() {
return consumer;
}
}
What is the exact reason for the fact that "capture of ?" cannot be used here and file does not compile?
GenericTools<?> tools = new GenericTools<>(Math::random, System.out::println);
tools.getConsumer().accept(tools.getSupplier().get());
Error:(27, 59) java: incompatible types: java.lang.Object cannot be converted to capture#1 of ?
With explicit <Double>
it compiles with no problems:
GenericTools<Double> tools = new GenericTools<>(Math::random, System.out::println);
tools.getConsumer().accept(tools.getSupplier().get());
I have used Java 1.8 to compile.
Please note that this is completely not a duplicate of Java generics “capture of ?”, where poster have no idea what we need to pass as "?"-typed argument when code requires it. In my case I am quite aware of capture mechanism, but stil type looking like supposed to work cannot be used. Most importantly, here I am asking about the exact reason (specification reference or something), not about what I should pass.
It's because the type ?
is invariant, and Object
is not a subtype of all types within the bounds of ?
.
I believe the Java 8 type inference is capable of inferring that T
is Double
on the RHS, but since you explicitly assign to a GenericTools<?>
on the LHS, the capture is of an unbounded type variable, which unifies with the unbounded variable T
which also has no bounds.
Without any bounds, the T
in the signatures of Supplier::get
and Consumer::accept
are not guaranteed to be the same type -- remember, the type variable is invariant, as no co- or contra-variant bound is expressed. The erasure of the T
on the Supplier
side is just Object
, and the compiler cannot insert a runtime check that the runtime type is actually ?
(because ?
is not reifiable!). Therefore: the type Object
cannot be implicitly converted to ?
and compilation fails.