10
public static void main(String[] args) {

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

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

}

The above code 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 fulfil ??

vines
  • 5,160
  • 1
  • 27
  • 49
Omnipotent
  • 27,619
  • 12
  • 30
  • 34

7 Answers7

5

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/

Matt Ball
  • 354,903
  • 100
  • 647
  • 710
Frank Grimm
  • 1,151
  • 7
  • 11
5

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.

rmaruszewski
  • 2,407
  • 1
  • 21
  • 21
2

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
  • 16,063
  • 3
  • 51
  • 65
1

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
  • 37
  • 2
  • No that's not right. At least from the second paragraph on the explanation is off-topic. It's not about type erasure. – jrudolph Sep 16 '08 at 07:55
  • 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 Sep 16 '08 at 18:48
0

Java Generics : Wild Cards in Collections

  1. extends
  2. super
  3. ?

Today I am going to explain you how the wild cards are useful. To understand this concept is bit difficult

Now Suppose you have abstract class and in that you have abstract method called paintObject().

Now you want to use different type of collection in every child class.

This below is AbstractMain Method.

Here Steps we have taken for this Abstract Main method

1. We have created abstract class

2. In Parameter we have define T(you can use any character) --In this case whichever class implement this method it can used any type of class. ex. Class can implement method like public void paintObject(ArrayList object) or public void paintObject(HashSet object)

3. And We have also used E extends MainColorTO -- In this case E extends MainColorTo -- It's clearly means whichever class you want to use that must be sub class of MainColorTo

4. We have define abstract method called paintObject(T object,E objectTO) --Now here whichever class is implement method that method can use any class on first argument and second parameter that method has to use type of MainColorTO

public abstract class AbstractMain<T,E extends MainColorTO> {
      public abstract void paintObject(T Object,E TO);  
}

Now we will extend above abstract class and implement method on below class ex.

public class MainColorTO {  
     public void paintColor(){
           System.out.println("Paint Color........");
     } 
  }

public class RedTO extends MainColorTO {
   @Override
   public void paintColor() {
   System.out.println("RedTO......");
 }
}
public class WhiteTO extends MainColorTO {
   @Override
   public void paintColor() {
     System.out.println("White TO......");
   }
 }

Now we will take two example.

1.PaintHome.java

public class PaintHome extends AbstractMain<ArrayList, RedTO> {
    @Override
    public void paintObject(ArrayList arrayList,RedTO red) {
        System.out.println(arrayList);

    }
 }

Now in above PaintHome.java you can check that we have used ArrayList in first argument(As we can take any class) and in second argument we have used RedTO(Which is extending MainColorTO)

2.PaintCar.java

public class PaintCar extends AbstractMain<HashSet, WhiteTO>{
    @Override
    public void paintObject(HashSet Object,WhiteTO white) {
        System.out.println(Object);

    }
 }

Now in above PaintCar.java you can check that we have used HashSet in first argument(As We Can take any class) and in second argument we have used WhiteTO(Which is extending MainColorTO)

Ponint to Remember You can not use super keyword at class level you can only use extends keyword at class level defination

public abstract class AbstractMain<P,E super MainColorTO> {

    public abstract void paintObject(P Object,E TO);

}

Above code will give you compiler error.

stackinfostack
  • 650
  • 2
  • 7
  • 12
0

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
  • 38,370
  • 19
  • 110
  • 156
0

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
  • 45,466
  • 8
  • 54
  • 65