1

I have following code:

public static void swap(List<?> list) {
    swapHelper(list); //1
}

private static <E> void swapHelper(List<E> list) {
    swap(list); //2
}

{
    List<?> tW = new ArrayList<>();
    List<E> tE = new ArrayList<>();

    tW = tE; // 3
    tE = tW; // 4
}

In this code line 1 and 2 compiles successfully, doesn't this mean: i can assign references of List<?> to that of List<E> and vice versa? If so then why line number 4 does not compile.

Ankush G
  • 989
  • 9
  • 14

1 Answers1

-2

Both <?> and <E> are unknown types; but all List<?>s have elements of some type, so you are able to call a method whose parameter is List<E>, because there is some unknown type which matches it.

Note that you can't do this:

public static void swap(Object object, List<?> list) {
    swapHelper(object, list); // Compiler error: object not in bounds of list.
}

private static <E> void swapHelper(E object, List<E> list) {
    swap(object, list); // OK.
}

because you now don't know if Object is within the bounds of List<?>.

Nor can you add new non-null values to the list:

private static <E> void swapHelper(List<E> list) {
    list.add(new E());  // Can't create an instance of type variable.
    swap(list);
}

but you can add values which you take from the list, since they are known to be within the bounds of the list:

private static <E> void swapHelper(List<E> list) {
    list.add(list.get(0));
    swap(list);
}

so it is type safe to do invoke the original swapHelper from swap, since you can't cause something which is not castable to E (whatever that type is) to the list.

Similarly with tW and tE:

  • If you assign tW = tE, you can't add anything to tW other than null, so you can't put tE in a state where it contains anything other than instances of E.
  • If you were allowed to assign tE = tW, you could add non-null instances of E to tE. This might mean that you could add an instance of the wrong class to tW, potentially leading to runtime type errors. As such, this assignment is forbidden.

Remember that assigning a list doesn't cause the list to be copied: if you assign tE = tW, then tE == tW, so all changes applied to tE are also visible via tW, since they are same instance.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243