I am using a method from a third party library (Reflections) which is supposed to find subtypes of the given type and looks like
public <T> Set<Class<? extends T>> getSubTypesOf(final Class<T> type) {
...
When the caller code looks like
Class<?> type = ...
Set<Class<?>> subTypes = reflections.getSubTypesOf(type);
I am getting a compile error: "cannot convert from Set<Class<? extends capture#19-of ?>> to Set<Class<?>>
". The following fixes the situation:
Class<?> type = ...
Set<?> subTypes = reflections.getSubTypesOf(ht);
so it looks like the only possible remedy for incorrect Set<Class<? extends ?>>
would be Set<?>
but not Set<Class<?>>
. Why is it so?
Thanks for any explanation on this.
Use the following instead:
Set<? extends Class<?>> subTypes = reflections.getSubTypesOf(type);
The problem is that nested wildcards don't perform type capture. Declaring a Set<Class<?>>
means "a set of classes of any type", while what's being returned is a Set<Class<? extends capture#19-of ?>>
, which means "a set of classes of any type extending from some specific unknown type". In this case, that "specific unknown type" is derived from the type argument to T
, which is inferred from type
to be an unbounded wildcard capture (the ?
in Class<?>
).
For example, pretend that "specific unknown type" is Number
:
Class<Number> type = ...
Set<Class<?>> subTypes = reflections.getSubTypesOf(type);
Here, getSubTypesOf
returns a Set<Class<? extends Number>>
. That type is not assignable to Set<Class<?>>
because generic types aren't covariant. But, wildcard capture helps us express covariance, allowing types like Set<? extends Class<?>>
. The caveat is that we can't add anything but null
to such a set, since we don't know its specific type.
Related posts:
Similar posts:
You must consider '?' means 'Unknown', not 'any'.
Set<Class<?>> subTypes = reflections.getSubTypesOf(type);
subTypes is a set of Class 'unknown'. It could be String, Integer, List... any of them.
getSubTypesOf(type) will return a certain but unknown set of classes. I use 'certain' because we know all will extend the class of type. So it's not the same. The problem is it seems you don't know the class of type on compilation time.
Set<Class>
should work too, but it will show a warning because you don't use the generic with Class.
As ?
is the wildcard, when you insert a Class<?>
, the method returns a Set<Class<? extends ?>>
(purely theoretical and not supported by Java) - try calling the method with a concrete type (e.g. Class<Number>
) and you should get a Set<Class<? extends Number>>
returned.
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