Java collection covariance problem

Let's say we have a program that contains such classes:

public interface AbstractItem {
}
public SharpItem implements AbstractItem {
}
public BluntItem implements AbstractItem {
}

public interface AbstractToolbox {
    //well the problem starts here...
    public List<AbstractItem> getItems();
}
public ExpensiveToolbox implements AbstractToolbox {
    private List<SharpItem> items = new ArrayList()<SharpItems>;
    public List<SharpItem> getItems() { return this.items; }
}
public CheapTooblox implements AbstractToolbox {
    private List<BluntItem> items = new ArrayList()<BluntItem>;
    public List<BluntItem> getItems() { return this.items; }
}

Easy, right? Well let's say, now we want to make such a method (in some random class):

public void doImportantStuff(AbstractToolbox toolbox) {
//important stuff!
//this obviously won't work
    List<AbstractToolbox> items = toolbox.getItems();
//do some stuffwith all items
}

Now the problem is that in Java collections with generics are not covariant (I hope that this term I am looking for), and I can not assign ArrayList<ExpensiveToolbox>for List<AbstractToolbox>. The only solution I see here is to duplicate the code and make a version for each type, but this is obviously a suck (what if we had more classes that implement AbstractToolbox with different lists?). Obviously, the second solution would be to give up generics and make a regular list, but is this a good practice?

Are there any design patterns / methods to solve such problems?

@Edit: ok, . , , AbstractToolbox, , AbstractItem, , AbstractToolbox - ( , AbstractItem, ).

+7
3

, , . : PECS ( )?

: List<? extends AbstractItem>

?

...

List<AbstractItem> foo = new ArrayList<SharpItem>();
foo.add(new BluntItem());

, ... ! ArrayList. .

List<? extends AbstractItem> foo = new ArrayList<SharpItem>();

, . , AbstractItems.

List (bare type) ?

, : -p

+18

. , :

interface AbstractToolbox {
    public List<? extends AbstractItem> getItems();
}

, , . getItems() ExpensiveToolbox CheapToolbox, , ..

ExpensiveToolbox toolbox = new ExpensiveToolbox();
AbstractToolbox absTB = toolbox;

List<? extends AbstractItem> items1 = absTB.getItems(); //fine
List<SharpItem> items2 = absTB.getItems(); //compile error
List<SharpItem> items3= toolbox.getItems(); //fine

AbstractToolbox:

public interface AbstractToolbox<T extends AbstractItem> {
    public List<T> getItems();
}
public ExpensiveToolbox implements AbstractToolbox<SharpItem> {
    public List<SharpItem> getItems() { //...
}
+4
public interface AbstractItem
{
}
public class SharpItem implements AbstractItem
{
}
public class BluntItem implements AbstractItem
{
}

public interface AbstractToolbox<T extends AbstractItem>
{
    public List<T> getItems();
}
public class ExpensiveToolbox implements AbstractToolbox<SharpItem>
{
    private List<SharpItem> items = new ArrayList<SharpItem>();
    public List<SharpItem> getItems() { return this.items; }
}
public class CheapToolbox implements AbstractToolbox<BluntItem>
{
    private List<BluntItem> items = new ArrayList<BluntItem>();
    public List<BluntItem> getItems() { return this.items; }
}


public void doImportantStuff(AbstractToolbox<?> toolbox)
{
    List<? extends AbstractItem> items = toolbox.getItems();

    for(AbstractItem item : items) 
        ... ;

}
0
source

All Articles