Java 泛型 : How does method inference work when wildcard is being used in the method parameters?

标签 java generics

假设我有以下内容:

class x {

public static void main(String [] args) {
    List <?> a = new LinkedList<Object>();
    List <? extends Object> b = new LinkedList<Object>();
    List <? super Object> c = new LinkedList<Object>();
    abc(a, "Hello"); // (1) Error
    abc(b, "Hello"); // (2) Error
    abc(c, "Hello"); // (3) ok  
    def(b); // (4) ok

// Showing inference at work
    Integer[] a = {10, 20, 30};  // (5)
    T is inferred to be ? extends Object
    Method signature: ppp(? extends Object, ? extends Object[])
    Method call signature: ppp(String, Integer[]);
    ppp("Hello", a); // ok

}

static <T> void abc(List<T> a, T b) {}  
static <T> void def(List<T> a) {}
static <T> void ppp(T t1, T[] t2){}

}  

首先,请看第 5 条显示推理在起作用。现在第 5 节是一个工作部分。

如果是这样,那么为什么条款(1)和(2)有错误?

在我看来,所有这 3 个方法调用都生成了相同的推断,因为在 abc 方法调用中没有使用实际类型参数。

方法参数 abc (List a, T b>)
推断 abc (List , Object)//(4)

请记住,方法 abc() 和 def() 是我的方法。编译器不知道我想用这个方法中的列表做什么。如上所示,我可能只打印列表大小,甚至可能根本不做任何事情。所以这里没有涉及 get 或 set。

继续 --> 这让我感到非常困惑。

class y {

public static void main(String [] args) {
    List <Integer> a = new LinkedList<Integer>();
    List <Object> b = new LinkedList<Object>();
    ppp("Hello", new Integer(1)); // (20) ok
    qqq("Hello", a); // (21) error
    qqq("Hello", b); // (22) ok
}

static <T> void ppp(T t1, T t2) {}
static <T> void qqq(T t1, List <T> t2) {}
}

请注意,第 21 条与第 20 条相同,只是第二个参数被设为列表而不是整数。

第 20 条是可以的,因为 T 被推断为对象。
第 22 条可以。与第 20 条相同的原因。 第 21 条失败? T 也可以被推断为对象 - 也可以吗?

最佳答案

通配符的难点在于实现? extends Foo 并不表示“任何扩展 Foo 的东西”,而是表示“扩展 Foo 的某些特定类型”。由于您在该定义之外,因此您无法知道 Foo 的特定子类型。

更新:

正如我所说,这很复杂。以下是对您的代码的一些评论。

// a list of some specific type, and you don't know what type that is.
// it's a sub-type ob Object, yes, which means that you can do
// Object foo = a.get(0); , but the compiler has no way of knowing
// whether it's a String so you can't pass in a String
List <?> a = new LinkedList<Object>();
// same here. '?' and '? extends Object' are equivalent
List <? extends Object> b = new LinkedList<Object>();
// this is a list of Objects and superclasses thereof.
// since there are no superclasses of Object, this is equivalent to
// List<Object>. And through inheritance, a String is an Object, so
// you can pass it in.
List <? super Object> c = new LinkedList<Object>();

更新 2:

这里的问题是您正在处理固定但无法解析的变量。

// you can pass in a List<String> and  a String,
// but if you pass in a List<?>, the compiler has no idea what
// '?' is and just can't substitute 'String'.
// 'T' doesn't help you here, because 'T' can't match both
// '?' and 'String'.
static <T> void abc(List<T> a, T b) {}  
// this works because 'T' substitutes '?' and doesn't have to worry
// about a 2nd parameter
static <T> void def(List<T> a) {}

阅读这个问题,它可能会阐明问题:

What is PECS (Producer Extends Consumer Super)?

关于Java 泛型 : How does method inference work when wildcard is being used in the method parameters?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7557316/