tags:

views:

826

answers:

6

public static void main(String[] args) {

 List<? extends Object> mylist = new ArrayList<Object>();

 mylist.add("Java"); // compile error

}

The above code (obviously) does not allow you to add elements to the list and wild cards can only be used as a signature in methods, again not for adding but only for accessing. In this case what purpose does the above fulfill??

A: 

With java generics using wildcards, you are allowed the above declaration assuming you are only going to read from it.

You aren't allowed to add/write to it, because all generic types must be stripped at compile time, and at compile time there isn't a way the compiler knows List are only strings, (it could be any object including strings!)

You are however allowed to read from it since they are going to be at least objects. Mixing different types are not allowed in java collections to keep things clean and understandable, and this helps ensure it.

Ren
No that's not right. At least from the second paragraph on the explanation is off-topic. It's not about type erasure.
jrudolph
The first paragraph isn't right either. You can remove from or add null to a list as declared in the question, you can also add (non-null) references if the wildcard is defined with a super bound.
Tom Hawtin - tackline
+1  A: 

The point of bounded wildcard types is their use in method signatures to increase API flexibility. If, for example, you implement a generic Stack<E>, you could provide a method to push a number of elements to the stack like so:

public void pushAll(Iterable<? extends E> elements) {
    for(E element : elements){
       push(e);
    }
}

Compared to a pushAll(Iterable<E> elements) signature without a wildcard, this has the advantage that it allows collections of subtypes of E to be passed to the method - normally that would not be allowed because an Iterable<String> is, somewhat counterintuitively, not a subclass of Iterable<Object>.

Henning
A: 

This works:

List<? super Object> mylist = new ArrayList<Object>();
mylist.add("Java"); // no compile error

From O'Reilly's Java Generics:

The Get and Put Principle: use an extends wildcard when you only get values our of a structure, use a super wildcard when you only put values into a structure, and don't use a wildcard you both get and put.

Stu Thompson
I think you meant `List<? super String>`.
Bruno De Fraine
No. I copied the example from above and replaced 'extends' with 'super'. That's it!
Stu Thompson
PECS = producer extends, consumer super
Helper Method
+4  A: 

Hello Omnipotent

In his book great 'Effective Java' (Second Edition) Joshua Bloch explains what he calls the producer/consumer principle for using generics. Josh's explaination should tell you why your example does not work (compile) ...

Chapter 5 (Generics) is freely available here: http://java.sun.com/docs/books/effective/generics.pdf

More information about the book (and the author) are available: http://java.sun.com/docs/books/effective/

HTH, Frank

Frank Grimm
A: 

List<? extends Object>, which is the same as List<?>, fulfills the purpose of generalizing all types List<String>, List<Number>, List<Object>, etc. (so all types with a proper type in place of the ?). Values of all of these types can be assigned to a variable of type List<?> (which is where it differs from List<Object>!).

In general, you cannot add a string to such a list. However, you can read Object from the list and you can add null to it. You can also calculate the length of the list, etc. These are operations that are guaranteed to work for each of these types.

For a good introduction to wildcards, see the paper Adding Wildcards to the Java Programming Language. It is an academic paper, but still very accessible.

Bruno De Fraine
+3  A: 

Let's say you have an interface and two classes:

interface IResult {}
class AResult implements IResult {}
class BResult implements IResult {}

Then you have classes that return a list as a result:

interface ITest<T extends IResult> {
  List<T> getResult();
}

class ATest implements ITest<AResult> {
  // look, overridden!
  List<AResult> getResult();
}

class BTest implements ITest<BResult> {
  // overridden again!
  List<BResult> getResult();
}

It's a good solution, when you need "covariant returns", but you return collections instead of your own objects. The big plus is that you don't have to cast objects when using ATest and BTest independently from the ITest interface. However, when using ITest interface, you cannot add anything to the list that was returned - as you cannot determine, what object types the list really contains! If it would be allowed, you would be able to add BResult to List<AResult> (returned as List<? extends T>), which doesn't make any sense.

So you have to remember this: List<? extends X> defines a list that could be easily overridden, but which is read-only.

Skillwired