5

I took a look on questions q1, q2, q3, but they don't cover exactly my question.

Note that ArrayList<A> and ArrayList<? extends A> are to be used for declaring a variable or a parameter (not for creating a new generic class).

Are both expressions equivalent when declaring an object attribute (case 1)?:

class Foo {

  private ArrayList<A> aList; // == ArrayList<? extends A> aList;
}

EDIT: Are both expressions equivalent from the point of view of what kind of objects are allowed to be added to aList?, but different in the same sense as the following case?

but they are different when used in a parameter declaration (case 2)?:

void methodFoo(ArrayList<A> al)  !=  void methodFoo(ArrayList<? extends A> al)

because the first one only allows to be passed ArrayList objects while the second would be like "more permissive" allowing to be sent ArrayList<A1> and ArrayList<A2> (as long as A1 and A2 extends A)?

If this is right, is there any other scenario where the two expressions are effectively different?

Thanks,

Community
  • 1
  • 1
cibercitizen1
  • 20,944
  • 16
  • 72
  • 95

6 Answers6

8

Let's have a look at some practical examples. Say, you have:

List<Number> list;

This means that whatever is assigned to this variable or field takes Number and outputs Number, so you always know what to expect. Integer can be added to this list since Integer extends Number. However, you can't assign, say, ArrayList<Long> to this list.

But consider this case:

List<? extends Number> list;

This one says: hey, that's a list of something that extends Number, but no one knows what exacty. What does this mean? This means that you can assign, for example, ArrayList<Long> to this list, which you couldn't in the first case. You still know that whatever this list outputs will be a Number, but you can't put an Integer in it anymore.

There is also an opposite case:

List<? super Number> list;

By printing that you say: that's a list of Number or its superclasses. This is where everything becomes vice-versa. The list can now refer to ArrayList<Object> and ArrayList<Number>. Now we don't know what this list will output. Will it be a Number? Will it be an Object? But now we know that we could put a Number in this list as well as any subclass of Number like Integer or Long.

There is a rule, by the way, which says producer extends, consumer super (PECS for short). If you need the list to output the values, it is a producer, this is the second case. If you need the list to accept values, it is a consumer, this is the third case. If you need both, don't use wildcards (that's the first case).

I hope this clears up matters.

Malcolm
  • 41,014
  • 11
  • 68
  • 91
  • @Malcom: good explanation on what type of things may be, or not, added to `list`. What about case 2: what type of lists a method can accept? – cibercitizen1 Apr 14 '12 at 10:46
  • @cibercitizen1 As I said in the answer, lists of something that extends `Number`. It could be something like `List` or `List`. Therefore you know that this list will give you a `Number`, but you don't know what you can put in it. – Malcolm Apr 14 '12 at 10:55
4

This will explain the difference:

public class GenericsTest {
  private ArrayList<A> la;
  private ArrayList<? extends A> lexta;

  void doListA(ArrayList<A> la) {}
  void doListExtA(ArrayList<? extends A> lexta) {}

  void tester() {
    la = new ArrayList<SubA>(); // Compiler error: Type mismatch
    doListA(new ArrayList<SubA>());  // Compiler error: Type mismatch
    lexta = new ArrayList<SubA>();
    doListExtA(new ArrayList<SubA>());
  }

  static class A {}
  static class SubA extends A {}
}

As you see, calling a method and assigning a variable/instance field have the same rules. Look at the method call as an assignment of your argument to its declared parameter.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
1

ArrayList<A> means a specific class A, where as ArrayList<? extends A> means class A or any class which extands A (Sub class of A) this make it more generic

Martijn Courteaux
  • 67,591
  • 47
  • 198
  • 287
Adil
  • 146,340
  • 25
  • 209
  • 204
1

Using private ArrayList<A> aList; as a variable declaration is not really equivalent to using the wildcard private ArrayList<? extends A> aList;

The wildcarded version will allow you to assign any ArrayLists of types that extend A and A itself but will refuse to add elements to the list as it cannot decide if it is type safe. With ArrayList<A> on the other hand you can only assign ArrayLists (or extensions of ArrayList) of type A and you can then add A elements and any elements extending A to it.

FYI: you should prefer using a more abstract type for declaring your variables/parameters like List<A> or Collection<A>.

nansen
  • 2,912
  • 1
  • 20
  • 33
0

It is hard to grasp at first, but inheritance doesn't apply with generics, ie if B extends A, List<B> is not a "subclass" of (can not be assigned to) List<A>. Further, List<? extends A> is not a "subclass" of (can not be assigned to) List<A>.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
0

The main difference is that if the generic form is used as an argument or return type in a method in a base class (or interface), it allows a greater range of type signatures to count as overriding instead of overloading.

Function override-overload in Java

For example, the following code is legal (in Java 7):

interface A
{
    List<? extends Number> getSomeNumbers();
}

class B implements A
{
    @Override
    public ArrayList<Integer> getSomeNumbers()
    {
        return new ArrayList<>();
    }
}

Difference between Enumeration<? extends ZipEntry> and Enumeration<ZipEntry>?

All of this means that sometimes you can write come code that requires less casts when someone else is using it. Which should not only reducing the amout of typing they have to do, but also eliminate possible failures.

Of course, the problem with Java generics is that they were introduced in a way that was constrained by backwards compatibility. So not everything works that you might think should, and the details get pretty hairy as to what exactly works and what doesn't.

http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#FAQ812

Community
  • 1
  • 1
soru
  • 5,464
  • 26
  • 30