38

I've read a few topics which cover certain questions about generics, such as their relationship with raw types. But I'd like an additional explanation on a certain line found in the Java SE tutorial on unbound generics .

According to a sentence :

The goal of printList is to print a list of any type, but it fails to achieve that goal — it prints only a list of Object instances; it cannot print List<Integer>, List<String>, List<Double>, and so on, because they are not subtypes of List<Object>.

If I understand well this sentence; the difference between List<?> and List<Object>, is that we can use the type argument List<String> or List<Integer> by implementing the former. While if we implement the later, we can only use the type argument List<Object>. As if List<?> is an upper bound to Object namely List<? extends Object>.

But then the following sentence confuses me, in the sense that according to what I previously understood, List<Object> should only contain instances of the class Object and not something else.

It's important to note that List<Object> and List<?> are not the same. You can insert an Object, or any subtype of Object, into a List<Object>. But you can only insert null into a List<?>.

Brad Cupit
  • 6,530
  • 8
  • 55
  • 60
Imad
  • 2,358
  • 5
  • 26
  • 55

2 Answers2

47

There are two separate issues here. A List<Object> can in fact take any object as you say. A List<Number> can take at least Number objects, or of course any subclasses, like Integer.

However a method like this:

public void print(List<Number> list);

will actually only take a List which is exactly List<Number>. It will not take any list which is declared List<Integer>.

So the difference is List<?> will take any List with whatever declaration, but List<Object> will only take something that was declared as List<Object>, nothing else.

The last quote simply states, that List<?> is a list for which you literally don't know what type its items are. Because of that, you can not add anything to it other than null.

Robert Bräutigam
  • 7,514
  • 1
  • 20
  • 38
  • 1
    And how about `List extends Number>`? – biziclop Feb 08 '16 at 15:22
  • 6
    `List extends Number>` would take any list that is *declared* to at least Number, so it would take `List` and `List` – Robert Bräutigam Feb 08 '16 at 15:24
  • 1
    That may be worth a mention, given that `List>` is somewhat analogous to `List extends Object>`. So the difference between `List` and `List>` is like the difference between `List` and `List extends Number>`. – biziclop Feb 08 '16 at 15:25
  • Is the assumption I made here correct? `As if List> is an upper bound to Object namely List Object>.` – Imad Feb 08 '16 at 15:27
  • *"Because of that, you can not do anything with it, other than to add `null`."* I guess you mean "you can not add anything to it, ...", because you can still perform other list operations on it. – Tom Feb 08 '16 at 16:11
  • `List>` and `List extends Object>` are idencial, not only "_somewhat analogous_". Its simply a shortcut. [Difference ...](https://stackoverflow.com/questions/8055389/whats-the-difference-between-and-extends-object-in-java-generics), [Nam Ha Minh](https://www.codejava.net/java-core/collections/generics-with-extends-and-super-wildcards-and-the-get-and-put-principle) – Marc Dzaebel May 26 '19 at 09:02
  • The one exception is that any ` extends ...>` type is seen as nonreifiable, while `t instanceof Interface>` is allowed. – Marc Dzaebel May 26 '19 at 09:18
  • 1
    Then what's the difference between `List` and `List>` ? – Parsa Noori May 31 '20 at 19:06
  • 1
    @ParsaNoori `List` with a missing generic parameter will mean `List`, for backward compatibility reasons. So, the same difference as `List` vs. `List>`. – Robert Bräutigam Jun 01 '20 at 07:55
22

The sentence that is confusing you is trying to warn you that, while List<?> is the super-type of all generic lists, you cannot add anything to a List<?> collection.

Suppose you tried the following code:

private static void addObjectToList1(final List<?> aList, final Object o ) {
    aList.add(o);
}

private static void addObjectToList2(final List<Object> aList, final Object o ) {
    aList.add(o);
}

private static <T> void addObjectToList3(final List<T> aList, final T o ) {
    aList.add(o);
}


public static void main(String[] args) {
    List<String> testList = new ArrayList<String>();
    String s = "Add me!";
    addObjectToList1(testList, s);
    addObjectToList2(testList, s);
    addObjectToList3(testList, s);
}

addObjectToList1 doesn't compile, because you cannot add anything except null to a List<?>. (That's what the sentence is trying to tell you.)

addObjectToList2 compiles, but the call to it in main() doesn't compile, because List<Object> is not a super type of List<String>.

addObjectToList3 both compiles and the call works. This is the way to add elements to a generic list.

Matthew McPeak
  • 17,705
  • 2
  • 27
  • 59