【问题标题】:java generic and wild cardjava泛型和通配符
【发布时间】:2011-11-12 17:54:51
【问题描述】:

在 java generic 中,我理解通配符、super 和 extends 的含义,但不明白为什么不允许我添加任何内容,以及为什么允许我在层次结构中添加到 SomeType,但在层次结构?

class Animal {}
class Cat extends Animal{}

以下方法可以获取动物列表或动物子的列表,即猫,但没有别的 而且我不允许添加任何东西,如果尝试添加,编译器会阻止我为什么?

void addAminal(List<? extends Aminal> aList){
       aList.add(new Cat()); // compiler error
       aList.add(new Animal()); // compiler error
}

现在下面的方法可以接受任何动物列表或任何超类型动物,但没有动物的子类型,并且我可以将对象添加到动物或层次结构更低的对象,所以当我尝试添加对象时,编译器会抱怨为什么?

void addAnimal(List<? super Animal> aList){
     aList.add(new Animal()); // no error
     aList.add(new Cat());     // no error
     aList.add(new Object()); // compiler error why ?
}

谢谢 艾莉亚

【问题讨论】:

标签: java generics wildcard


【解决方案1】:

假设你定义了一个新类:

class Tabby extends Cat {}

然后你做了以下事情:

List<Tabby> aList = new ArrayList<Tabby>();
addAnimal(aList);

毫无疑问,这个列表不应该有动物甚至不是虎斑猫,但如果编译器没有标记错误,那就是你应该有的。

原因是你已经指定addAnimal 来获取扩展Animal 的东西的列表,但是这可能是高度限制的。但是,这将编译:

void addAnimal(List<Animal> aList){
    aList.add(new Cat()); // OK
    aList.add(new Animal()); // OK
}

super 的使用也可以,因为CatAnimal 的实例是Animal 的任何超类的实例。

【讨论】:

  • 感谢泰德的回复。我的疑问是 List extends Aminal> 将是 Animal 或 Animal 子类型的列表,因此它应该完美地找到将 Animal 或 Animal 子类型添加到 List,我们可以使用 List l = new ArrayList(); l.add(new Animal()); l.add(new Cat()),这行得通,所以当它是 List extends Aminal> 为什么它不起作用?
  • 它不起作用,因为List&lt;? extends Animal&gt; 不是可以包含 Animal 或 Animal 子类型的列表。它是 Animal 的某个子类型的列表,它不会接受任何不是该子类型的子类型的东西。 (特别是,它可能不接受 Animal,就像我的第一个示例一样。)只需使用 List&lt;Animal&gt; 作为方法的正式参数,就可以了。
【解决方案2】:

List&lt;? extends Animal&gt; 表示List&lt;X&gt;,其中XAnimal 的未知子类型。

因此它有方法

void add(X item);
X get(int i);

你不能调用 add(cat),因为我们不知道 Cat 是否是 X 的子类型。由于 X 是未知的,我们知道的唯一值是 X 的子类型是 @987654328 @,所以你可以add(null),但没有别的。

我们可以做Animal a = list.get(i),因为该方法返回X,而XAnimal的子类型。所以我们可以调用get(i),把返回值当作Animal。

相反,List&lt;? super Animal&gt; 表示List&lt;Y&gt;,其中YAnimal 的未知超类型。现在我们可以调用add(cat),因为Cat是Animal的子类型,Animal是Y的子类型,因此Cat是Y的子类型,add(Y)接受一个Cat。另一方面,Animal a = list.get(0) 现在不能工作,因为 Animal 不是返回类型 Y 的超类型; Y 唯一已知的超类型是 Object,所以我们能做的只有 Object o = list.get(0)

【讨论】:

    【解决方案3】:

    泛型仅允许您添加作为类型参数给出的类型的类型(或子类型)的对象。如果您输入&lt;? extends Animal&gt;,则表示该列表具有某种类型,它是动物的子类。由于您尝试向其中添加 Cat,因此您必须确保它确实是 Cats 列表,而不是 Dogs 列表。
    基本上,当您使用通配符时,您将无法将新项目添加到这样的列表中(注意:我没有完整的知识,这可能不完全正确,但看起来像这样。如果我是,请原谅我错了)

    如果您希望能够将任何动物添加到列表中,只需使用List&lt;Animal&gt;

    【讨论】:

    • 感谢史蒂文的回复。我明白你在说什么。我没有得到的是为什么 不允许我添加任何内容,该列表可能包含 Animals 或 Animal 的子类型,有什么危害?
    • 它可能不包含“动物或子类型”。它是一个类型的列表(由“?”表示),它是 Animal 的子类。查看 Ted Hopp 的示例,他尝试使用您的代码将 Cat 添加到 Tabbies 列表中,这显然是不允许的。
    【解决方案4】:

    好吧,当您说 ArrayList 您指定此列表将包含任何特定类型(因为 ? 指的是特定/确定类型)是 Animal 类型或任何从 Animal 继承但 确定 的东西。所以最终,由于泛型是用 Eraser 概念实现的(它用非泛型上限替换程序中的每个泛型类型),这个列表应该包含一个特定的类型,但是由于 ( ) 你不知道那是哪个 specific 类型。因此,即使类型是从 Animal 继承的,也不允许添加。

    但是当你说 ArrayList,表示arraylist包含从Animal派生的特定类型,即基类或超类为Animal的对象。因此,将 Animal 或从 Animal 派生的任何东西传递到此列表中是安全的。该列表以这种方式处理,并且允许添加提到的对象。因此它起作用了。

    希望对你有帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多