Generics and the mystical wildcard

This comes up a lot on the forums (or should that be fora?).

“I’ve got a List<?>, why can’t I put an object of type X in it?” (for any type X).

The problem here is that most people see the ? and interpret it as “anything” when in fact it means “something concrete, but unknown at compile time”.

Eh?

You heard me. You don’t have a “list of anything” there, you have a “list of something… I’m just not sure what”.

Eh?

Right then. From the top.

List<?> means a “list of something”. That something could be Integer, or String, or Socket, or Trousers. It doesn’t matter. To put that into context, all of the following are legal:

List<?> list;
list = new LinkedList<Integer>();
list = new LinkedList<String>();
list = new LinkedList<Socket>();
list = new LinkedList<Trousers>();

Notice something there? You can assign any of those lists to your list reference variable. So, further down in the code, how can the compiler know exactly what type of list your variable refers to?

Again… a concrete example:

List<?> list = new LinkedList<String>();
someMethod(list);
// ...

public void someMethod(List<?> l) {
    // what type of objects does l contain here?
}

OK, in this example we can see that l refers to a List<String>. But it’s not hard to envisage this code being called from multiple call sites making it impossible for any static analysis to tell us what the list contains.

Now, back to the beginning…

You don’t have a “list of anything” there, you have a “list of something… I’m just not sure what”.

So in the example, l is not a “list of anything”, it’s a “list of something”. In this case, it’s a “list of String”, but at a different call site, it could be “list of Integer” or even a list of those world-famous trousers!

For this reason, the compiler won’t let you put anything into the list. Some people refer to these collections as “read-only”. They’re not intrinsically read-only, it’s just that you can’t pass anything to the add(E o) method that will satisfy the compiler when E is ? (well, you can pass null but that’s not hugely useful). Hence why these collections are, in effect, read-only.

The is-a relationship hasn’t gone away

The next question that typically arises is “So, how can I make a list that contain any object?”

Setting aside the design issue with this, the answer is simple: List<Object>.

For some reason, Java Generics appear to blind people to the age-old object-oriented is-a relationship. Anywhere that you have to provide an instance of class X, you can provide instead an instance of class Y provided Y extends (directly or indirectly) from X or else that Y implements (directly or indirectly) X, if X is an interface.

List<Object> is a list that contains instances of Object. From our Object Oriented Programming class, and our pseudo-definition of the is-a relationship, we can see that you can put any decendant of Object into this list. Apart from the intrinsic types, this covers every type in the system. This list can contain anything.

How do I make a list that contains both an Integer and a Double? Well, you can’t get that explicit, but List<Number> does the trick thanks to our is-a relationship. Of course, this list can also contain Float, Long, etc.

That was a pretty brief run-down of what’s going on with Generics and wildcards. I hope you found it useful.

Share this:
Facebook Twitter Digg Email

This entry was posted in Generics, Java. Bookmark the permalink.

One Response to Generics and the mystical wildcard

  1. Stephen says:

    Excellent explanation. The succinct “of something…that is unknown” phrase is great. Thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>