Java Collections of Interfaces
I'm writing a small API to deal with objects that have specific 'traits' In this case, they all have an interval of time and a couple of other bits of data, So I write an interface TimeInterval with some getters and setters.
Now most of these API methods deal with a Set or List of Objects. Internally these methods use the Java Colletions Framework (HashMap/TreeMap in particular). So these API methods are like:
getSomeDataAboutIntervals(List<TimeInterval> intervalObjects);
Couple of Questions:
a) Should this be List<? extends TimeInterval> intervalObjects
instead?
Is it mostly a matter of style? The one disadvantage of taking strictly an interface that I can see is, you need to create your list as a List<TimeInterval>
rather than List<ObjectThatImplementsTimeInterval>
.
This means potentially having to copy a List<Object..>
to List<TimeInterval>
to pass it to the API.
Are there other pros & cons to either approach?
b) And, one dumb question :) The collections framework guarantees I always get out the same instance I put in, the col开发者_运维百科lections are really a collection of references, correct?
1) Yes.
Method parameters should be as general as possible. List<? extends A>
is more general than List<A>
, and can be used when you don't need to add things to the list.
If you were only adding to the list (and not reading from it), the most general signature would probably be List<? super A>
Conversely, method return types should be as specific as possible. You rarely to never want to return a wildcard generic from a method.
Sometimes this can lead to generic signatures:
<T extends MyObject> List<T> filterMyObjects(List<T>)
This signature is both as specific and as general as possible
2) Yes, except possibly in some rare very specific cases (I'm thinking of BitSet
, although that isn't technically a Collection
).
If you declare your list as List<? extends A>
, then you can pass in any object which static type is List<X>
, where X extends A
if A
is a class, or X implements A
id A
is an interface. But you'll not be able to pass in a List
or a List<Object>
to it (unless A
is Object
) without force-casting it.
However, if you declare the parameter as a List<A>
, you'll only be able to pass lists which static type is strictly equivalent to List<A>
, so not List<X>
for instance. And by "you are not able to do otherwise", I really mean "unless you force the compiler to shut up and accept it", which I believe one should not do unless dealing with legacy code.
Collections are really collections of references. The abstraction actually is that everything you can put in a variable is a reference to something, unless that variable is of a primitive type.
1) I would recommend ? extends TimeInterval. Because of Java's polymorphism, it may not actually make a difference, but it is more robust and better style
2) Yes
a) No. List<? extends TimeInterval>
will only accept interfaces that extend the interface TimeInterval. Your assertion that "you need to create your list as a List<TimeInterval>
is wrong, unless I misunderstand your point. Here's an example:
List<List> mylist= new ArrayList<List>();
mylist.add(new ArrayList());
b) Yes.
Should this be List intervalObjects instead?
You only do that if you want to pass in a List<TimeIntervalSubclass>
. Note you can put instances of subclasses of TimeInterval
into a List<TimeInterval>
. Keep in mind that the type of the list is different than the types in the list.
If you do List<? extends A> myList
-- that only affects what you can assign to myList
, which is different than what is in myList
.
And, one dumb question :) The collections framework guarantees I always get out the same instance I put in, the collections are really a collection of references, correct?
When you create a collection Map myMap = new HashMap()
, myMap
is a reference to the underlying collection. Similarly, when you put something into a collection, you are putting the reference to the underlying object into the collection.
精彩评论