Java collections covariance problem

前端 未结 3 1128
情话喂你
情话喂你 2020-12-03 18:04

Lets say we have a program which contains such classes:

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


        
相关标签:
3条回答
  • 2020-12-03 18:24

    Here are a couple of extra ideas. Leave everything the same, but use this:

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

    This basically says that the abstract class' items are an unknown type, but subclasses can make it concrete. This would require you to call getItems() on a reference of type ExpensiveToolbox or CheapToolbox to be able to retrieve a list that allows you to add items, etc.

    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
    

    Alternatively, you could just type AbstractToolbox:

    public interface AbstractToolbox<T extends AbstractItem> {
        public List<T> getItems();
    }
    public ExpensiveToolbox implements AbstractToolbox<SharpItem> {
        public List<SharpItem> getItems() { //...
    }
    
    0 讨论(0)
  • 2020-12-03 18:37
    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 讨论(0)
  • 2020-12-03 18:49

    You're probably going to need to take a look at using wildcard types for generics. Here's a quick link: What is PECS (Producer Extends Consumer Super)?

    Quick answer: change the type to List<? extends AbstractItem>

    Why can't you just assign this?

    Imagine the code here...

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

    The static typing says this should work... but you can't do that! It would violate the ArrayList's type. That's why this is disallowed. If you change it to

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

    you can then do the assignment, but never add anything to the list. You can still retrieve elements from the list, however, as AbstractItems.

    Is just using List (bare type) a good solution?

    No, definitely not :-p

    0 讨论(0)
提交回复
热议问题