Java 下界通配符

Java Lower Bound Wildcard

下面main方法中的List怎么编译通过?

class Breakfast {

}

class Drink extends Breakfast {

}

class Juice extends Drink {

}

class Food extends Breakfast {

}

class Bread extends Food {

}

public static void main(String[] args) {

    Object object = new Object();
    Drink drink = new Drink();
    Juice juice = new Juice();
    Bread bread = new Bread();

    List<? super Drink> firstList = Arrays.asList(object, drink, juice, bread);

    List<?> secondList = Arrays.asList(object, drink, juice, bread);

    List<? extends Drink> thirdList = Arrays.asList(drink, juice, bread); //DOESN'T COMPILE
}

看来面包不是饮料的超类?允许编译第一个和第二个列表但不允许编译第三个列表的规则是什么?如果是这样,那么

之间的主要区别是什么
<?>  

<? super Drink>

谢谢!

extends 是一个 upper 边界 - 这意味着指定的任何实例在继承层次结构中必须没有 "higher" 指定类型。

根据您的示例,? extends Drink 是上限 - 因此每个对象都必须从 Drink 扩展才能合法分配到该列表中。

super 是一个 较低的 边界 - 这意味着指定的任何实例在继承层次结构中必须不是指定类型的 "lower"。

根据您的示例,? super Drink 是下限 - 因此每个对象都必须是 Drink 的类型或其祖先的类型 - 在这种情况下,Object .

? 是一个通配符 - 如果您正在使用它,您实际上 不关心 集合中的类型是什么(因为您无法得到它信息返回)。默认情况下,结果为 ? extends Object,因此上限规则适用(并且满足)。

Java 编译器使用类型推断来确定调用泛型方法(例如 Arrays.asList)的类型参数。它确定可以派生为所有参数的超类型的最具体类型。

对于第一个和第二个列表,列表中有一个Object,所以Object是推断类型参数。这适用于 ? super Drink,因为 ? super DrinkObject 满足的下限。这也适用于无界通配符 ?,因为 ? 将匹配任何推断类型参数。只要您对这两个列表变量使用不同的名称,它们就会编译。

对于第三个列表(称为 fourthList?),您有一个下限 ? extends Drink,这意味着推断的类型必须是 Drink 的子类型,或者 Drink本身或一个子类。因为 Breakfast 是推断类型,而 Breakfast 不是 Drink 的子类型,所以这是一个编译器错误。如果 Bread 不在列表中,则推断的类型将为 Drink,这将编译。