-1

In the below example "Apple" is the super type of anything that can be added to the array. In the example below "Apple" or any of its subtypes are allowed to be added to the list. However only "Object" instances are allowed to be retrieved. Since only Apple and it's subtypes are allowed , why doesn't Java allow the values to be mapped to "Apple" instances?

class Fruit {
   @Override
   public String toString() {
      return "I am a Fruit !!";
   }
}
 
class Apple extends Fruit {
   @Override
   public String toString() {
      return "I am an Apple !!";
   }
}
 
class AsianApple extends Apple {
   @Override
   public String toString() {
      return "I am an AsianApple !!";
   }
}
 
public class GenericsExamples
{
   public static void main(String[] args)
   {
      //List of apples
      List<Apple> apples = new ArrayList<Apple>();
      apples.add(new Apple());
       
      //We can assign a list of apples to a basket of apples
      List<? super Apple> basket = apples;
       
      basket.add(new Apple());      //Successful
      basket.add(new AsianApple()); //Successful
      basket.add(new Fruit());      //Compile time error
      basket.add(new Object());     //Compile time error

      Object fruit1 = basket.get(0); //works
      Apple appleFruit = basket.get(0); // compiler error
   }
}
Punter Vicky
  • 15,954
  • 56
  • 188
  • 315

1 Answers1

2

Perhaps you misunderstood what List<? super Apple> means. With it, you can totally do something like this:

List<? super Apple> apples = new ArrayList<Object>();

I can certainly not get Apples from apples now, can I?

Since Java doesn't know at compile time what apple actually is (Is it a Arraylist<Object> or ArrayList<Apple>?), it can't allow you to get Apples out of it.

The point of List<? super Apple> is to allow you to put any type of List into the apples variable, as long as that type is Apple or one of its superclasses. Because of this, it is limited what you can put into this list (Apple or its subclass) and what you can get out of it (Object only).

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • Thanks! So I can do something like this - ```List myList = new ArrayList<>(); myList.add(new Object()); List super Number> contravariantList = myList;```. What is the difference between defining a List vs List super Apple>? In the latter case when I use "add" , I am able to add only Apple or its subtypes , but can't wrap my head around the significance. – Punter Vicky Oct 13 '20 at 02:02
  • 1
    @PunterVicky Read my last paragraph again. You can't do `List apples = new ArrayList();`, can you? `List super Apple>` allows you to do that, with some restrictions. – Sweeper Oct 13 '20 at 02:10
  • 1
    @PunterVicky And before you say "But I can use `List apples = new ArrayList()`!"... What if you want a variable that can store both `ArrayList` and `ArrayList`? You'd need a `ArrayList super Apple>`. For more info on when to use wildcards, see [this](https://stackoverflow.com/questions/16707340/when-to-use-wildcards-in-java-generics). – Sweeper Oct 13 '20 at 02:18
  • This clarifies a lot of things for me. So incase of covariant (? extends Apple) create a readonly list which contains apple or its subtypes. This is typically passed as parameter to a method. The contravariant list (? super Apple) can have either Apple or its supertypes including Object , hence only Object can be read from it. How would the calling method determine the type of Object to do anything useful? – Punter Vicky Oct 13 '20 at 03:13
  • 1
    @PunterVicky If the calling method needs to know the type, then you wouldn't use ` super Apple>` :-) It is only used when the method doesn't care about what kind of list it is, as long as it is a list into which `Apple`s can be inserted. In other words, methods that only puts stuff into the list (treating it as a consumer) would accept ` super Apple>`, and methods that only gets stuff from the list (treating it as a producer) would accept ` extends Apple>`. See also: [PECS](https://stackoverflow.com/questions/2723397/what-is-pecs-producer-extends-consumer-super). – Sweeper Oct 13 '20 at 03:27
  • 1
    If a method needs to do both, then it only makes sense for it to accept a `List`. @PunterVicky – Sweeper Oct 13 '20 at 03:27