无法使用通配符编译相关的Java泛型参数

无法使用通配符编译相关的Java泛型参数,java,generics,nested-generics,Java,Generics,Nested Generics,以下小Java示例无法编译,原因不清楚: 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 At

以下小Java示例无法编译,原因不清楚:

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);
    }
}
包一般性问题;
导入java.util.ArrayList;
导入java.util.List;
接口属性{}
接口ListAttribute扩展属性列表=新建ArrayList();
ctx.put(ListAttribute.class,list);
}
}
带有ctx.put的行产生以下错误:

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 ?>)
Context.java:18:put(java.lang.Class,T)在genericsissue中。上下文不能应用于(java.lang.Class,java.util.List)
如果不使用通配符,则属性模式可以正常工作

有没有解释为什么编译器不接受通配符类型的值?

Replace

public <T, A extends Attribute<T>>
公共


public问题是,
list
的参数类型实际上不是
list
。编译器首先执行“通配符捕获”,将其类型转换为某些x的
列表。通常,这会提供更多信息和帮助。但对你来说不是。它促使类型推断认为
T=List
,但
listtribute
不扩展
属性

您可以提供显式类型参数来解决此问题

ctx.<List<?>, ListAttribute>put(ListAttribute.class, list);
      (T)      (A)

ctx。这可能是类型推断系统的一个限制。试试:
ctx。你的问题表达得很好!SSCCE、错误消息等。上周的相关问题:鉴于我们不知道
put
的实现,您怎么能认为这是正确的?那么它是类型安全的吗?因为在我看来,我可以将超类型层次结构中的所有实例作为值,这不是我想要允许的。我认为我们可以假设这是可以的,因为您必须记住,
value
可以是
T
的任何子类。因此,如果
是一个
字符串
a
可以是
属性
属性
,或者现在的
属性
。这唯一能防止的是从
a
生成
T
,这似乎是合理的。经过一段时间的思考后,听起来是合理的。这才是真正的解决方案,也是类型安全的,因为属性类型可以在类型层次结构中占据更高的位置。“它现在就像一个符咒,”马克·彼得斯-没关系,但不应该是必须的
T
在推理过程中足够自由,因此
属性
应该可以工作。顺便说一句,OP的代码是用Java8编译的。这个解决方案满足编译器的要求,但不满足最初创建的模式,该模式是为了避免像类型转换和显式类型参数这样的冗长提示。@iterator-您的原始代码现在用不同的推理规则在Java8中编译。然而,它也有可能在java7中工作,但是javac中有一个bug。不确定。
ctx.<List<?>, ListAttribute>put(ListAttribute.class, list);
      (T)      (A)