返回 Collection<? extends Type> 和 Collection<Type> 有何区别?

5
这两种方法有什么区别?
Collection<Type> getTypes();

vs

Collection<? extends Type> getTypes();

类型是类还是接口有关系吗? 特别是在设计API时,应该优先选择哪个版本?为什么?


这里需要注意的一点是:Collection<Type>Collection<SubType>(其中SubType扩展了Type)并不相同。 - rocketboy
3个回答

8
Collection<Type> getTypes();

在这里,getTypes() 必须返回一个 Collection<Type>(例如 ArrayList<Type>HashSet<Type>)。请注意,不要更改或删除 HTML 标签。
Collection<? extends Type> getTypes();

在这里,getTypes()可以返回任何一个是或继承了TypeCollection(例如ArrayList<SubType>HashSet<SubType>)。因此,第一种情况下可以返回的任何内容也可以从第二种情况下返回。但是,在第二种情况下,您不知道集合的类型参数实际上是什么;您只知道它扩展了Type
至于哪种方法应该优先选择,这实际上取决于您正在尝试做什么以及逻辑上更有意义的事情。请记住,当您使用<? extends Type>时,您实际上不知道?是什么,有时这可能会妨碍您;通常第一种情况更合适。您可以在基类中使用第二种情况,并在子类中覆盖它,使其更类似于第一种情况,例如:
@Override
Collection<SubType> getTypes() {
    ...
}

@user2707634 对的,你无法安全地向“Collection<? extends Type>”添加任何内容,因为你不知道类型参数实际上是什么。 - arshajii
2
@stonedsquirrel 一个带有返回类型为Collection<? extends Type>的方法可以返回Collection<Type> - arshajii
@arshajii 当然。我误解了你的句子。抱歉!即使我错误地告诉了你,我的评论声明仍然是正确的;-) - André Stannek
1
不完全是只读,因为 clear() 方法仍然有效,一些迭代器可以 delete() - Judge Mental
@stonedsquirrel:你的评论毫无意义。你说Collection<? extends Type>不能包含类型为Type的对象,然后你又说它可以。 - Louis Wasserman
显示剩余3条评论

3
通常不建议使用通配符类型作为返回值类型,详细原因请参见泛型 FAQ。简而言之,这可能会使返回的对象变得无用(或更少有用),因为使用类型参数的参数方法只能使用“null”进行调用。例如,在Collection中:
Collection<? extends Type> collection = ...
collection.add(null); // OK
collection.add(anInstanceOfType); // Error

在这种情况下,这会防止向集合中添加任何内容(这似乎不是一件坏事,有人试图使用此方法使返回的集合“只读”,在这里),但一般来说这可能会引起问题。

不回答“这两种方法有什么区别?”但仍然是一个很好的参考。 - Paul Bellora

0

<? extends Type> 是一个有边界的通配符泛型。以这种方式定义的集合可以是类型的任何子类或者 Type 本身。

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

在这种情况下,唯一重要的是 ?Type 类型。

Collection<Type> 必须返回一个 Type 的集合。例如:

Collection<Type> collection;

点击此处查看更多信息,具体选择取决于您的需求。

以下是一个例子。当定义可呈现的项目组时,我使用有界通配符。例如:

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);

任何获取/设置例程都返回我指定的类型(PhysicalSprite、ParticleSprite),这是理想的。

如果我定义为:

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

我需要将它们转换为特定于每种类型的Sprite的属性。任何SpriteGroup的子类也会受到同样的限制。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接