Java Generics (Wildcards)
Asked Answered
A

7

126

I have a couple of questions about generic wildcards in Java:

  1. What is the difference between List<? extends T> and List<? super T>?

  2. What is a bounded wildcard and what is an unbounded wildcard?

Arcuation answered 30/10, 2008 at 22:57 Comment(1)
In the case that Ted Gao's answer is deleted (since it was link-only), here is the blog post to which it linked.Drivel
C
137

In your first question, <? extends T> and <? super T> are examples of bounded wildcards. An unbounded wildcard looks like <?>, and basically means <? extends Object>. It loosely means the generic can be any type. A bounded wildcard (<? extends T> or <? super T>) places a restriction on the type by saying that it either has to extend a specific type (<? extends T> is known as an upper bound), or has to be an ancestor of a specific type (<? super T> is known as a lower bound).

The Java Tutorials have some pretty good explanations of generics in the articles Wildcards and More Fun with Wildcards.

Calica answered 30/10, 2008 at 23:10 Comment(5)
Just to get it right, if A < B and B < C then: <A extends C> is wrong?Arcuation
If by A < B, you mean A extends B, then A does extend C. You wouldn't use that in the wildcard syntax though, you'd say <? extends C> to limit your choices to either A or B.Calica
and in that case if I say <? super C> what would be the difference?Arcuation
Just wanted to recommend another reference on Java Generics: angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.htmlEldest
@Pablo: <? super C> would mean that your type is restricted to something above C in the type hierarchy. (Sorry for the extremely late reply. I guess we didn't have comment notifications 2 years ago?)Calica
R
55

If you have a class hierarchy A, B is a subclass of A, and C and D are both subclasses of B like below

class A {}
class B extends A {}
class C extends B {}
class D extends B {}

Then

List<? extends A> la;
la = new ArrayList<B>();
la = new ArrayList<C>();
la = new ArrayList<D>();

List<? super B> lb;
lb = new ArrayList<A>(); //fine
lb = new ArrayList<C>(); //will not compile

public void someMethod(List<? extends B> lb) {
    B b = lb.get(0); // is fine
    lb.add(new C()); //will not compile as we do not know the type of the list, only that it is bounded above by B
}

public void otherMethod(List<? super B> lb) {
    B b = lb.get(0); // will not compile as we do not know whether the list is of type B, it may be a List<A> and only contain instances of A
    lb.add(new B()); // is fine, as we know that it will be a super type of A 
}

A bounded wildcard is like ? extends B where B is some type. That is, the type is unknown but a "bound" can be placed on it. In this case, it is bounded by some class, which is a subclass of B.

Rellia answered 30/10, 2008 at 23:14 Comment(1)
I assume List<? super B> describes as List accepts the type that is parent class of class B? Which is why C and D won't compile hmm?Interphase
Q
39

Josh Bloch also has a good explanation of when to use super and extends in this google io video talk where he mentions the Producer extends Consumer super mnemonic.

From the presentation slides:

Suppose you want to add bulk methods to Stack<E>

void pushAll(Collection<? extends E> src);

– src is an E producer

void popAll(Collection<? super E> dst);

– dst is an E consumer

Quantic answered 31/10, 2008 at 8:15 Comment(3)
I've read Bloch's book, but I still can't see the difference between extends and super in this particular case.Arcuation
Watch the video, I think it's pretty clear. Also, I think you should ask another question on this "what's the difference between List<? extends T> and List<? super T>" where you will hopefully get more answers. (if you do, add a link from here)Quantic
Beds--why not include the example in this answer to make it complete and stand alone. Links are ephemeral.Unlettered
G
4

There may be times when you'll want to restrict the kinds of types that are allowed to be passed to a type parameter. For example, a method that operates on numbers might only want to accept instances of Number or its subclasses. This is what bounded type parameters are for.

Collection<? extends MyObject> 

means that it can accept all object who have IS- A relationship with MyObject (i.e. any object which is a type of myObject or we can say any object of any subclass of MyObject) or a object of MyObject class.

For example:

class MyObject {}

class YourObject extends MyObject{}

class OurObject extends MyObject{}

Then,

Collection<? extends MyObject> myObject; 

will accept only MyObject or children of MyObject(i.e. any object of type OurObject or YourObject or MyObject, but not any object of superclass of MyObject).

Galengalena answered 8/1, 2015 at 9:47 Comment(0)
L
1

In general,

If a structure contains elements with a type of the form ? extends E, we can get elements out of the structure, but we cannot put elements into the structure

List<Integer> ints = new ArrayList<Integer>();
ints.add(1);
ints.add(2);
List<? extends Number> nums = ints;
nums.add(3.14); // compile-time error
assert ints.toString().equals("[1, 2, 3.14]"); 

To put elements into the structure we need another kind of wildcard called Wildcards with super,

 List<Object> objs = Arrays.<Object>asList(2, 3.14, "four");
    List<Integer> ints = Arrays.asList(5, 6);
    Collections.copy(objs, ints);
    assert objs.toString().equals("[5, 6, four]");

    public static <T> void copy(List<? super T> dst, List<? extends T> src) {
          for (int i = 0; i < src.size(); i++) {
                dst.set(i, src.get(i));
         }
    }
Louls answered 20/6, 2015 at 16:34 Comment(0)
P
1

Generic wildcards are created to make methods that operate on Collection more reusable.

For example, if a method has a parameter List<A>, we can only give List<A> to this method. It is a waste for this method's funtion under some circumstances:

  1. If this method only reads objects from List<A>, then we should be allowed to give List<A-sub> to this method. (Because A-sub IS a A)
  2. If this method only inserts objects to List<A>, then we should be allowed to give List<A-super> to this method. (Because A IS a A-super)
Phototype answered 7/12, 2016 at 9:26 Comment(0)
D
0

learn by example:

consider the sort() method in Collections class which use both extends and super:

    public static <T extends Comparable<? super T>> void sort(List<T> list){...}

so

why <T extends Comparable<...>>: becuase we need list items (T) to be a subclass of the Comparable interface.

why Comparable<? super T>: becuase we allow the Comparable type to be a Comparable of any super type of T.

Consider

interface Comparable<T>{
    public int compareTo(T o);
}

public static <T extends Comparable<? super T>> void sort(List<T> list){...}


public static <T extends Comparable<T>> void sort2(List<T> list){...}


class A implements Comparable<A>{
    @Override
    public int compareTo(A o) {
        ...
    }
}

class B extends A {
}

    List<A> listA = new ArrayList<>();
    List<B> listB = new ArrayList<>();

    sort(listA);  //ok
    sort(listB);  //ok
    
    sort2(listA); //ok
    sort2(listB); //Error
Dendy answered 8/5, 2022 at 11:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.