Videos
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.
The easy way to think of it is: Collections beat object arrays in basically every single way. Consider:
- A collection can be mutable or immutable. A nonempty array must always be mutable.
- A collection can allow or disallow null elements. An array must always permit null elements.
- A collection can be thread-safe; even concurrent. An array is never safe to publish to multiple threads.
- A list or set's
equals,hashCodeandtoStringmethods do what users expect; on an array they are a common source of bugs. - A collection is type-safe; an array is not. Because arrays "fake" covariance,
ArrayStoreExceptioncan result at runtime. - A collection can hold a non-reifiable type (e.g.
List<Class<? extends E>>orList<Optional<T>>). An array will generate a warning for this. - A collection can have views (unmodifiable, subList...). No such luck for an array.
- A collection has a full-fledged API; an array has only set-at-index, get-at-index, length and clone.
- Type-use annotations like
@Nullableare very confusing with arrays. I promise you can't guess what@A String @B [] @C []means. - Because of all the reasons above, third-party utility libraries should not bother adding much additional support for arrays, focusing only on collections, so you also have a network effect.
Object arrays will never be first-class citizens in Java APIs.
A couple of the reasons above are covered -- but in much greater detail -- in Effective Java, Third Edition, Item 28, from page 126.
So, why would you ever use object arrays?
- You're very tightly optimizing something
- You have to interact with an API that uses them and you can't fix it
- so convert to/from a
Listas close to that API as you can
- so convert to/from a
- Because varargs (but varargs is overused)
- so ... same as previous
- Obviously some collection implementations must be using them
- I can't think of any other reasons, they suck bad
It's basically a question of the desired level of abstraction.
Most collections can be implemented in terms of arrays, but they provide many more methods on top of it for your convenience. Most collection implementations I know of for instance, can grow and shrink according to demand, or perform other "high-level" operations which basic arrays can't.
Suppose for instance that you're loading strings from a file. You don't know how many new-line characters the file contains, thus you don't know what size to use when allocating the array. Therefore an ArrayList is a better choice.