1

I have a Box class as shown below.

public class Box <E> {

private List<E> itmes = new ArrayList<>();

public void addItem(E e){
    itmes.add(e);
}

public void addItemList(List<? extends E> itemList){
    itmes.addAll(itemList);
}

public List<E> getItems(){
    return itmes;
}

}

The first implementation uses unbounded type arguments, which works fine. As shown below

    Box<Apple> appleBox = new Box<>();
    Apple fujiApple = new Apple("fujiApple");
    Apple kashmiriApple = new Apple("kashmiriApple");
    appleBox.addItem(fujiApple);
    appleBox.addItem(kashmiriApple);

    Box<Orange> orangeBox = new Box<>();
    Orange weirdOrange = new Orange("weirdOrange");
    Orange orangeOrange = new Orange("orangeOrange");
    orangeBox.addItem(weirdOrange);
    orangeBox.addItem(orangeOrange);

    Box<Fruit> fruitBoxAll = new Box<>();
    fruitBoxAll.addItemList(appleBox.getItems());
    fruitBoxAll.addItemList(orangeBox.getItems());

But now, I want to use bounded type argument as shown below

    Box<? extends Fruit> fruitBox = new Box<>();

Declaring ? extends Fruit as type argument means that List inside Box class will also be of type ? extends Fruit. And following code will give an error

fruitBox.addItem(fujiApple);

As at some point later, user may try to add oranges to the same list

fruitBox.addItem(orangeOrange);

which is not right. So I cannot use this bounded type argument object to create a Box of sub-type of Fruit. Which is understandable from Java point of view, but then using bounded type arguments seem not useful.

So from the implementation perspective, I have following questions:

  1. Is using bounded type arguments a right approach?
  2. If Yes, What type of elements can it contain in the scenario explained above.
  3. Can you throw in an example, where bounded type arguments are useful or the right scenario/way to implement them.
Meena Chaudhary
  • 9,909
  • 16
  • 60
  • 94
  • A collection `? extends Fruit` is supposed to be a producer of fruit instances, you can never add anything to it. Look up PECS concept. You can only read from that collection. If you need to add instances use `? super Fruit` – TheLostMind Dec 20 '15 at 06:11
  • I found another question, little similar to your question. It might be of some help [http://stackoverflow.com/questions/2575363/generics-list-extends-animal-is-same-as-listanimal](http://stackoverflow.com/questions/2575363/generics-list-extends-animal-is-same-as-listanimal) – Roy S Dec 20 '15 at 06:12
  • What is the type hierarchy for `Apple` and `Orange`? They should be subclasses of `Fruit`. – hotzst Dec 20 '15 at 06:12
  • @hotzst - I think they are. The OP seems to have a good idea about basic java :) – TheLostMind Dec 20 '15 at 06:14
  • Look up [PECS](http://stackoverflow.com/questions/2723397/java-generics-what-is-pecs) – TheLostMind Dec 20 '15 at 06:14
  • @hotzst `Apple` & `Orange` are subclasses of `Fruit` – Meena Chaudhary Dec 20 '15 at 06:23
  • @VinodMadyalkar But why is it that after changing ` extends Fruit>` to ` super Fruit>`, items in the List returned by `getItems()` do not support methods from `super` class? I am getting an error for method in super class as undefined for the type `? super Fruit`. Also, what is the type of items in this list, isn't it `Fruit`? – Meena Chaudhary Dec 20 '15 at 07:23

1 Answers1

0

As others have pointed out what you're doing is covered by the PECS idea - Produce Extends, Consumer Super. You should really read Difference between <? super T> and <? extends T> in Java

Your problem with List is that the list is declared as some type which is a specific subclass of Fruit but you're trying to treat it as a list of Fruit, which is not typesafe.

Where it's useful to use the ? extends Fruit bounded type is when you're returning a list to a client who will a) only ever try to read from the list and b) who only cares that objects in the list implement the Fruit interface.

e.g.

public void myMethod() {
    List<? extends Fruit> myList = theListProducingMethod();
    for (Fruit f: myList) {
        f.fruitMethod();
    }
}

public List<? extends Fruit> theListProducingMethod() {
    final List<Orange> someList = new ArrayList<>();
    someList.add(new Orange());
    return someList;
}

The thing to note here is that the returned list is effectively immutable in myMethod. Because its generic type is <? extends Fruit> there's no way to call myList.add in myMethod in a type safe fashion.

sisyphus
  • 6,174
  • 1
  • 25
  • 35