2

I ask this question because of a discussion about one answer here on Stack. The statement is the following:

Given the following code:

List<?> list =new ArrayList<Integer>();

Why can't we do:

Integer e = 2;
list.add(e);

This throws a compiler error, despite the fact that we instantiated the list as an ArrayList<Integer>.

Why is that ?

Yassine Badache
  • 1,810
  • 1
  • 19
  • 38
  • 2
    because you explicitly have taken information away from the compiler, the compiler does not know the *actual* type of the instance at runtime, it knows only the type you write down: `List>`. – luk2302 Apr 11 '18 at 15:40

2 Answers2

4

Because a List<?> could be any sort of List (List<String> for example). And the compiler should not permit adding the wrong type to a list.

However, if you know the actual class then you can do a class cast at runtime:

((List<Integer>)list).add(e);

Code like this should be avoided since it can generate a ClassCastException if an unexpected type is encountered at runtime. To make matters worse (as noted by luk2302), our ClassCastException might only occur in an entirely different area of the code-- namely, when we are retrieving something from the list.

A better approach

If you know that the list will be of a specific type or a superclass of that type, then you could define the variable using a bounded wildcard:

List<? super Integer> list;
Integer e = 2;

list = new ArrayList<Integer>();
list.add(e);

list = new ArrayList<Number>();
list.add(e);

list = new ArrayList<Object>();
list.add(e);

This approach, as noted by M. Prokhorov, allows us to avoid the need for an inadvisable cast.

Patrick Parker
  • 4,863
  • 4
  • 19
  • 51
  • 2
    Note that the code shown will **not** produce a `ClassCastException`, not even for `List` - it will run just fine, only when retrieving something from the list a `ClassCastException` might occur. – luk2302 Apr 11 '18 at 15:51
  • Should also note that compiler will permit adding elements to a list which is defined as `? super T`, where it would allow adding elements of `T` or any superclass thereof (except when `T` is interface, you can't add `Object` to the mix, that one won't work). – M. Prokhorov Apr 11 '18 at 15:59
  • I would make the casting approach the last part of the answer, rather than the first part. No one should *ever* be doing an unsafe cast like that. – VGR Apr 11 '18 at 16:41
0

Just create an Arraylist of and they will let you add all, because Integer, String and Boolean are child or in other words Object class is their parent.

anon
  • 7
  • It does not the "why" question, tho. The question is not here to find a workaround (I already have one), it is to provide information on *why* this behavior happens. Remember it when it comes to answering questions. – Yassine Badache Apr 12 '18 at 07:08