0

Given that Manager extends Employee

I was surprised to get a compiler error when I try to add an Employee to an ArrayList of Managers,

   ArrayList<? super Manager> sonsOfEmployee = new ArrayList<>();
    sonsOfEmployee.add(new Employee("Manager",100000));

I get error

Required type: capture of ? super Manager

likejudo
  • 3,396
  • 6
  • 52
  • 107
  • 2
    `ArrayList super Manager> sonsOfEmployee = new ArrayList();` compiles. If `Manger` is a _subtype_ of `Employee`, then it would make sense that you can't add an `Employee` to a `List`, wouldn't it? – Louis Wasserman Feb 26 '22 at 00:05
  • @LouisWasserman Please look at the question carefully. it is not a List – likejudo Feb 26 '22 at 20:48
  • I did look at the question carefully. An `ArrayList super Manager>` _could_ be an `ArrayList` as far as Java is concerned, and that's why it's not allowing this assignment. – Louis Wasserman Feb 26 '22 at 23:34
  • @LouisWasserman so why can't we add an `Employee` to `ArrayList`? After all it fits the rule we have set: `? super Manager` is allowed. – likejudo Feb 27 '22 at 01:11
  • No. `List super Manager>` does not mean what you think it means, you have it backwards. `List super Manager>` means that it's a `List` for some _fixed but unknown_ type `T` that is `Manager` or one of its supertypes. It is _not_ a `List` containing anything that is a supertype of `Manager`. – Louis Wasserman Feb 27 '22 at 01:17
  • @LouisWasserman To me, your two statements here are equivalent I can't see how they are different. {Louis] "1) a List for some fixed but unknown type T that is Manager or one of its supertypes. ....2) a List containing anything that is a supertype of Manager" – likejudo Feb 27 '22 at 02:18
  • You'll need to think harder about my first comment, then. What would you expect to happen with the following code: `List managerList = new ArrayList<>(); List super Manager> superManagerList = managerList; superManagerList.add(new Employee("Manager", 100000)); System.out.println(managerList);` If this code worked, you would have an `Employee` in a `managerList`, which is impossible. – Louis Wasserman Feb 27 '22 at 02:37
  • @LouisWasserman But there are other generics code examples that also show ridiculous output involving String and Number ArrayLists and yet they compile fine. – likejudo Feb 27 '22 at 23:16
  • 1
    You're welcome to ask questions about those, then, but the code example I gave in my last comment is the reason this doesn't work. – Louis Wasserman Feb 28 '22 at 00:12

1 Answers1

2

Lower-bounded generic collections (Collection<? super A>) are writable - that's correct.

First, let's examine what type of collection we can assign to it.

List<? super Manager> means that you can assign to this list a list of managers, a list of employees, a list of objects. All these assignments are perfectly valid and all of them will compile:

List<? super Manager> list;
list = new ArrayList<Manager>();
list = new ArrayList<Employee>();
list = new ArrayList<Object>();

That means that under the hood of list can appear any of these lists. We know for sure only that could be a list of type Manager or its super-types. And if it will be an ArrayList<Manager> you can't put an Employee object into this collection.

We can put an instance of Manager into the Collections<Employee> but not the other way around.

Let's consider another example:

ArrayList<? super String> list1 = new ArrayList<>();
list1.add((CharSequence) "Java"); // that will not compile
    
ArrayList<? super CharSequence> list2 = new ArrayList<>();
list2.add("Java");

Adding an object of type CharSequence to the ArrayList<? super String> will fail to compile because the interface CharSequence is a super-type of String.

But we can add a string to ArrayList<? super CharSequence> because String is compatible with CharSequence type.

Alexander Ivanchenko
  • 25,667
  • 5
  • 22
  • 46
  • I don't understand your sentence - it is not an Arraylist. It is an ArrayLis that contains suprttype of Manager... which is Employee. You said, "nd if it will be an ArrayList you can't put an Employee object into this collection." – likejudo Feb 26 '22 at 20:52
  • Isn't Charsequence following the rule by being a supertype of String? [Alexander] "Adding an object of type CharSequence to the ArrayList super String> will fail to compile because the interface CharSequence is a super-type of String." – likejudo Feb 27 '22 at 01:09
  • 1
    @likejudo You misunderstand. `ArrayList super String>` **isn't an actual type**. In plain words, generics provide a way to tell the compiler that type we don't know what the type is. `` and *wild cards* are not the real types. `ArrayList super String>` exist only in the source code. All generic information will be replaced with type casting. That process is called [generic erasure](https://docs.oracle.com/javase/tutorial/java/generics/genTypes.html). – Alexander Ivanchenko Feb 27 '22 at 02:24
  • 1
    @likejudo At runtime, we will have an `ArrayList` or `ArrayList` (technically an `ArrayList` that maintains `Object[]` which elements will be casted into `String` or `Manager` type when we call `get()` on this collection). – Alexander Ivanchenko Feb 27 '22 at 02:28
  • Following the PECS rule,`ArrayList super String>` even if I add an instance of a supertype of String, it will fail? – likejudo Feb 27 '22 at 23:21
  • @likejudo Please reread my two previous comments. You are confusing the **type of the reference** (like `ArrayList super String>`) and the actual **type of the object** (which can be `ArrayList` or `ArrayList`). Now forget about generics for a second and answer the *question:* can you add an instance of `Object` to the `ArrayList`? The answer is **no**, right? For the same reason you can't add an instance of `Object` to `ArrayList super String>`, a **real collection** which is under the hood of this wild-card reference could be `ArrayList`. Is it clear now? – Alexander Ivanchenko Feb 27 '22 at 23:57