The following little Java example won't compile for unclear reasoning:
package genericsissue;
import java.util.ArrayList;
import java.util.List;
interface Attribute<V> {}
interface ListAttribute extends Attribute<List<?>> {}
public class Context {
public <T, A extends Attribute<T>> void put(Class<A> attribute, T value) {
// implementation does not matter for the issue
}
public static void main(String[] args) {
Context ctx = new Context();
List<?> list = new ArrayList<String>();
ctx.put(ListAttribute.class, list);
}
}
The line with ctx.put produces following error:
Context.java:18: <T,A>put(java.lang.Class<A>,T) in genericsissue.Context cannot be applied to (java.lang.Class<genericsissue.ListAttribute>,java.util.List<capture#35 of ?>)
If working without wildcards the attribute pattern works fine.
Is there any explanation why the compiler does not accept the value with wildcard typing?
The problem is, the argument type of list
is not really List<?>
. Compiler does a "wildcard capture" first to convert its type to List<x> for some x
. Usually this is more informative and helpful. But not in your case. It drives type inference to think that T=List<x>
, but ListAttribute
does not extend Attribute<List<x>>
You can provide explicit type arguments to work around it
ctx.<List<?>, ListAttribute>put(ListAttribute.class, list);
(T) (A)
Replace
public <T, A extends Attribute<T>>
With
public <T, A extends Attribute<? super T>>
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