【问题标题】:Returning Collection<? extends Type> vs Collection<Type>返回集合<?扩展类型> vs 集合<类型>
【发布时间】:2013-08-25 07:35:47
【问题描述】:

这两种方法有什么区别?

Collection<Type> getTypes();

Collection<? extends Type> getTypes();

Type 是类还是接口有关系吗? 特别是在设计 API 时,首选哪个版本?为什么?

【问题讨论】:

  • 这里要注意一件重要的事情:Collection&lt;Type&gt; 与 SubType 扩展 Type 的 Collection&lt;SubType&gt; 不同。

标签: java generics wildcard extends


【解决方案1】:
Collection<Type> getTypes();

在这里,getTypes() 必须返回 Collection&lt;Type&gt;(例如 ArrayList&lt;Type&gt;HashSet&lt;Type&gt;)。

Collection<? extends Type> getTypes();

在这里,getTypes() 可以返回 Collection 的任何内容或扩展 Type,(例如 ArrayList&lt;SubType&gt;HashSet&lt;SubType&gt;)。所以任何可以从第一个变体返回的东西也可以从第二个变体返回。但是,在第二种情况下,您不知道集合的类型参数实际上是什么;你只知道它扩展了Type

至于应该首选哪个,这实际上取决于您要做什么,以及在逻辑上更有意义的事情。请记住,当您拥有&lt;? extends Type&gt; 时,您实际上并不知道? 是什么,这有时会造成阻碍;通常第一个变体更合适。您可以在基类中使用第二个变体,并在子类中用更类似于第一个的东西覆盖它,例如:

@Override
Collection<SubType> getTypes() {
    ...
}

【讨论】:

  • 这是否意味着返回的Collection&lt;? extends Type&gt; 实际上变成了只读的?否则客户将如何添加到集合中?
  • @user2707634 是的,您不能安全地向Collection&lt;? extends Type&gt; 添加任何内容,因为您不知道类型参数实际上是什么。
  • “可以返回任何类型或扩展类型的集合”。错误的! Collection&lt;? extends Type&gt; 不能包含 Type 类型的对象。它必须是一个子类型。 Collection&lt;? extends Type&gt; 可以同时包含两者。这是我认为两者之间的主要区别之一。
  • @stonedsquirrel 返回类型为Collection&lt;? extends Type&gt; 的方法可以返回Collection&lt;Type&gt;
  • 不是只读的,因为clear() 方法仍然有效,一些迭代器可以delete()
【解决方案2】:

一般不鼓励使用通配符类型返回,详细原因见Generics FAQ。简而言之,它可以使返回的对象变得无用(或不那么有用),因为使用类型参数的参数方法只能用'null'调用。例如,Collection:

Collection<? extends Type> collection = ...
collection.add(null); // OK
collection.add(anInstanceOfType); // Error

在这种情况下,这会阻止向集合中添加任何内容(这不是一件坏事,似乎有人使用它来尝试使返回的集合成为“只读”,here),但通常这会导致问题.

【讨论】:

  • 不回答“这两种方法有什么区别?”但仍然是一个很好的参考。
【解决方案3】:

&lt;? extends Type&gt; 是一个有界通配符泛型。以这种方式定义的集合可以是任何类型的子类,或Type。即。

Collection<Type> typeCollection;
//or
Collection<SubType> subtypeCollection;
//where subtype is...
class SubType extends Type

在这种情况下,重要的是 ? 的类型为 Type

Collection&lt;Type&gt; 必须返回Type 的集合。即。

Collection<Type> collection;

阅读tutorials here. 了解更多信息。您选择哪个取决于您的需求。

这是一个例子。我在定义可渲染项组时使用有界通配符。例如。

public class SpriteGroup<T extends Sprite>

这将是 Sprites 或 Sprite 的任何子类的集合。这很有用,因为我可以像这样定义组:

SpriteGroup<PhysicalSprite> physicalSprites = new SpriteGroup<PhysicalSprite>();
PhysicalSprite physicalSprite = physicalSprites.get(0);
SpriteGroup<ParticleSprite> particleSprite = new SpriteGroup<ParticleSprite>();
ParticleSprite particle = particleSprite.get(0);

然后,任何 get/set 例程都会返回我指定的类型(PhysicalSprite、ParticleSprite),这是可取的。

如果我将其定义为:

SpriteGroup<Sprite> spriteGroup = new SpriteGroup();
//all I can retrieve is a sprite, gotta cast now...
Sprite sprite = spriteGroup.get(0);

我需要强制转换它们以访问特定于每种 Sprite 类型的属性。 SpriteGroup 的任何子类都将受到同样的限制。

【讨论】:

    猜你喜欢
    • 2011-05-17
    • 1970-01-01
    • 1970-01-01
    • 2019-04-09
    • 1970-01-01
    • 1970-01-01
    • 2013-04-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多