Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ArrayList with generics declaration in Java

The following code gives me an error for the line l.add

List<? extends Number> l = new ArrayList<Integer>();
l.add(1);

and forces me to write it as l.add(1, null);

Why is it so?

like image 274
user1079065 Avatar asked Jul 18 '14 21:07

user1079065


2 Answers

With a wildcard on the variable l, the compiler doesn't know (or care) which subclass of Number (or Number itself) the type parameter really is. It could be an ArrayList<Double> or an ArrayList<BigInteger>. It can't guarantee the type safety of what's passed in to add, and because of type erasure, the JVM can't catch a type mismatch either. So the compiler preserves type safety by disallowing such calls to add unless the value is null, which can be any type.

To get add to compile, you must declare l as:

List<? super Integer> l = new ArrayList<Integer>();

or you can remove the wildcard:

List<Integer> l = new ArrayList<Integer>();
like image 80
rgettman Avatar answered Sep 28 '22 09:09

rgettman


It has to be:

List<? super Integer> l = new ArrayList<Integer>();
l.add(1);

Note the <? super Integer> declaration. It's called an upper-bound wildcard.

What does it do?

It restricts the Runtime type of the elements of the ArrayList to be one of the super classes of Integer, e.g. Integer, Number or Object, which means that you will be able to assign l to:

  • new ArrayList<Integer>
  • new ArrayList<Number>
  • new ArrayList<Object>

In the three cases, the statement l.add(1) is perfectly valid, so there's no compile-time error.

More info:

  • Upper-bounded wildcards in Java
  • What is PESC?
like image 24
Konstantin Yovkov Avatar answered Sep 28 '22 09:09

Konstantin Yovkov