Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Failing to compile correlated Java Generics parameters with wildcards

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?

like image 737
iterator Avatar asked May 17 '13 15:05

iterator


2 Answers

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)
like image 160
ZhongYu Avatar answered Oct 04 '22 13:10

ZhongYu


Replace

public <T, A extends Attribute<T>>

With

public <T, A extends Attribute<? super T>>
like image 43
Arnaud Denoyelle Avatar answered Oct 04 '22 13:10

Arnaud Denoyelle