Java中的通配符问题

Mos*_*she 0 java wildcard

鉴于以下课程

class Creature {}
class Animal extends Creature {}
class Dog extends Animal {}
Run Code Online (Sandbox Code Playgroud)

以下列表

List<? super Animal> l1;
List<? extends Animal> l2;
Run Code Online (Sandbox Code Playgroud)

哪些命令会导致编译错误?

1) l1.add(new Dog())
2) l1.add(null)
3) Object a = l1.get(0)
4) l2.add(new Dog())
5) Creature c = l2.get(0))
Run Code Online (Sandbox Code Playgroud)

我认为这是四,因为? extends Animal不一定是超类型Dog,但我不完全确定.解释会有很大帮助:)

Clo*_*ger 5

超级和延伸

该行List<? super Animal> l1;意味着l1可以实例化列表以保存超类型的对象Animal.例:l1 = new LinkedList<Creature>();

该行List<? extends Animal> l2;意味着l2可以实例化列表以保存子类型的对象Animal.例:l2 = new LinkedList<Dog>();

答案

假设列表已构建.

1)列表l1可以被实例化以保存任何超类型Animal.由于它Dog是任何超类型的子类型,Animal因此可以隐含地进行铸造.编译.

2)总是编译.规范List并不否定空值.运行时异常取决于列表实现是否允许null元素.LinkedList允许空值.

3)隐式转换为超类型(每个对象都是类的实例Object)总是编译.如果列表为空,则在运行时导致异常.

4)add方法的签名List<? extends Animal> l2l2.Add(? extends Animal).当我们调用l2.Add(new Dog())编译器时无法确定该类型?是否为超类型Dog(因为它不知道是什么?,因为我们明确地使用List接口调用该方法而不是通过实现List),因此它必须导致编译错误.

来自评论: "但请注意,此问题与引用容器时使用接口无关.如果在声明中使用ArrayList而不是lList,则会发生相同的编译错误." - 德克

5)假设额外的括号是错误的.总是隐式转换为超类型编译.Creature是列表l2可以容纳的任何类型的超类型.如果列表为空,则在运行时导致异常.

  • 1现在读得很好,虽然`Dog`不需要转换为`Animal` - 一个`Dog`*的实例是*一个`Animal`.无论你做什么,4都不会编译.`名单<?extends X>`表示该列表包含一些未定义的`X`子类的实例.除了转换列表之外没有任何东西可以使编译器接受对`add`的调用. (3认同)