我正在编写一个小API来处理具有特定“特征”的对象。在这种情况下,它们都有一个时间间隔和几个其他数据位,所以我用一些getter写了一个接口TimeInterval setter方法。
现在,大多数这些API方法都处理一组或一组对象。在内部,这些方法使用Java Colletions Framework(特别是HashMap / TreeMap)。所以这些API方法就像:
getSomeDataAboutIntervals(List<TimeInterval> intervalObjects);
几个问题:
a)这应该是List<? extends TimeInterval> intervalObjects
吗?
这主要是风格问题吗?严格按照我可以看到的界面的一个缺点是,您需要将列表创建为List<TimeInterval>
而不是List<ObjectThatImplementsTimeInterval>
。
这意味着可能需要将List<Object..>
复制到List<TimeInterval>
以将其传递给API。
还有其他专业人士吗?两种方法都有缺点?
b)而且,一个愚蠢的问题:)集合框架保证我总是得到我放入的相同实例,集合实际上是一组引用,对吗?
答案 0 :(得分:2)
1)是的。
方法参数应尽可能通用。 List<? extends A>
比List<A>
更通用,可以在不需要向列表添加内容时使用。
如果您只是添加到列表中(而不是从中读取),则最常见的签名可能是List<? super A>
相反,方法返回类型应尽可能具体。您很少想永远不想从方法中返回通配符。
有时这会导致通用签名:
<T extends MyObject> List<T> filterMyObjects(List<T>)
此签名既具体又通用
2)是的,除了可能在一些罕见的非常具体的情况下(我正在考虑BitSet
,尽管从技术上讲这不是Collection
)。
答案 1 :(得分:1)
如果您将列表声明为List<? extends A>
,那么您可以传入静态类型为List<X>
的任何对象,X extends A
如果A
是类,或{ {1}} id X implements A
是一个界面。但是,如果没有强行投射,您将无法传递A
或List
(除非List<Object>
为A
)。
但是,如果将参数声明为Object
,则只能传递静态类型严格等同于List<A>
的列表,因此不能传递List<A>
。并且通过“你无法做到”,我的意思是“除非你强迫编译器闭嘴并接受它”,我认为除非处理遗留代码,否则不应该这样做。
集合实际上是引用的集合。抽象实际上是你可以放入变量的所有内容都是对某事物的引用,除非该变量属于基本类型。
答案 2 :(得分:1)
1)我会推荐?扩展TimeInterval。由于Java的多态性,它可能实际上没有区别,但它更健壮,风格更好
2)是的
答案 3 :(得分:0)
a)否。List<? extends TimeInterval>
只接受扩展接口TimeInterval的接口。你的断言“你需要将你的列表创建为List<TimeInterval>
是错误的,除非我误解了你的观点。这是一个例子:
List<List> mylist= new ArrayList<List>();
mylist.add(new ArrayList());
b)是的。
答案 4 :(得分:0)
这应该是List intervalObjects吗?
如果您想传递List<TimeIntervalSubclass>
,则只能这样做。请注意,您可以将TimeInterval
的子类实例放入List<TimeInterval>
。请注意,列表的类型与列表中的类型不同。
如果您执行List<? extends A> myList
- 只影响您可以分配给myList
的内容,这与 myList
中的不同。
而且,一个愚蠢的问题:)集合框架保证我 总是拿出我放入的同一个实例,这些收藏品确实如此 一组参考文献,对吗?
创建集合Map myMap = new HashMap()
时,myMap
是对基础集合的引用。类似地,当您将某些内容放入集合时,您将对基础对象的引用放入集合中。