简体   繁体   English

如何对列表使用子类型多态和泛型?

[英]How to use subtype polymorphism & generics for lists?

I'm learning Java, and have read about inheritance and subtype polymorphism. 我正在学习Java,并已阅读有关继承和子类型多态性的知识。 Now I'm just starting to learn about generics, and I'm trying to put the pieces together, but am stuck. 现在,我才刚刚开始学习泛型,并且试图将各个部分放在一起,但被卡住了。

Say I've an abstract parent class AbstractEdibles , and there are two children that extend from it: Food and Drink . 说我一个abstract父类AbstractEdibles ,并有两个孩子是extend从它: FoodDrink Also, I've a Store that has two List s: one to store Food and one to store Drink . 另外,我的Store有两个List :一个用于存储Food ,另一个用于存储Drink

Now, I want my Store to be able to have behaviors, such as adding to its stock. 现在,我希望我的Store能够有某种行为,例如增加库存。 My desired approach is to define one method to take in a product and put it in the appropriate list. 我想要的方法是定义一种方法来接收产品并将其放入适当的列表中。 If it's a Food type, put it in the food list. 如果是Food类型,请将其放入食物清单。 If it's of type Drink , put it in the drink list. 如果是Drink类型,则将其放入饮料列表中。

I'm sure I need to use generics and subtype polymorphism. 我确定我需要使用泛型和子类型多态性。 Here's a snippet of my code: 这是我的代码片段:

public class Store {

  private List<AbstractEdible> foodStock = new ArrayList<>();
  private List<AbstractEdible> drinkStock = new ArrayList<>();

  /**
   * A constructor for a new store inventory that has food and drink.
   *
   * @param foodStock   the list of food items in stock
   * @param drinkStock  the list of drink items in stock
   */
  public Store(List<AbstractEdible> foodStock, List<AbstractEdible> drinkStock) {
    this.foodStock = foodStock;
    this.drinkStock = drinkStock;
  }

  /**
   * Given an edible food, add it to its respective stock list.
   *
   * @param edible an edible item
   */
  public void addItemToStock(AbstractEdible edible) {
    if (product instanceof Food) {
      this.foodStock.add(product);
    } else if (product instanceof Drink) {
      this.drinkStock.add(product);
    }
  }
}

This doesn't give errors, but I'm unhappy with how loose I'm being with the types, and I think it could be made more optimal. 这不会产生错误,但是我对类型的松散度感到不满意,我认为可以将其优化。

For starters, I'd prefer to allow my list to only allow that specific type of edible . 首先,我希望允许我的清单允许该特定类型的edible That is, foodStock will only allow Food to be added, and drinkStock will only allow Drink to be added. 也就是说, foodStock仅允许添加Food ,而drinkStock仅允许添加Drink What I tried was: 我试过的是:

private List<AbstractEdible> foodStock = new ArrayList<Food>();
private List<AbstractEdiblet> drinkStock = new ArrayList<Drink>();

gives me a red underline in my IDE. 在我的IDE中给我一个红色下划线。 So then I changed to: 因此,我更改为:

private List<Food> foodStock = new ArrayList<Food>();
private List<Drink> drinkStock = new ArrayList<Drink>();

this works, but then my addItemToStock() method complains that the edible I'm trying to add is of type Edible and can't be added to a List containing type Food . 这工作,但后来我addItemToStock()方法抱怨说, edible我想补充的是类型的Edible ,不能被添加到List包含类型Food (This is expected, because Edible is the parent of Food ; ie not every Edible is a Food , but every Food is Edible .) (这是预料之中的,因为EdibleFood的父项;即,并非每种Edible都是Food ,但是每种Food都是Edible 。)

Up/Down casting edible doesn't help, either. 上下浇铸edible也无济于事。 I then thought Upper Bounded Wildcards was what I was looking for, but that also didn't work. 然后我以为我想要的是上界通配符 ,但这也没有用。

Besides that, I'm also unsure if using instanceof is the best way to classify/sort objects. 除此之外,我也不确定使用instanceof是否是对对象进行分类/排序的最佳方法。

What am I missing here? 我在这里想念什么? What concept am I not understanding? 我不了解什么概念?

If you want to ensure that foodStock stores Food only and drinkStock stores Drink only, then you'll have to initialize your lists like this: 如果你想确保foodStockFood只和drinkStockDrink而已,那么你就必须初始化列表如下:

private List<Food> foodStock = new ArrayList<>();
private List<Drink> drinkStock = new ArrayList<>();

If they are coming from constructor, just declare them: 如果它们来自构造函数,则只需声明它们:

private List<Food> foodStock;
private List<Drink> drinkStock;

and then assign them in constructor: 然后在构造函数中分配它们:

public Store(List<Food> foodStock, List<Drink> drinkStock) {
    this.foodStock = foodStock;
    this.drinkStock = drinkStock;
}

And once you have used instanceOf , it is safe to use casting: 并且一旦您使用instanceOf ,就可以安全地使用casting:

public void addItemToStock(AbstractEdible product) {
    if (product instanceof Food) {
        this.foodStock.add((Food) product);
    } else if (product instanceof Drink) {
        this.drinkStock.add((Drink) product);
    }
}

You could also create a generic Stock class: 您还可以创建一个通用的Stock类:

public class Stock<T extends AbstractEdible> {

    private List<T> items;

    public Stock() {
        items = new ArrayList<>();
    }

    public void addItem(T item) {
        this.items.add(item);
    }

    public List<T> getItems() {
        return items;
    }
}

and use it in your Store as: 并在您的Store中将其用作:

public class Store {
    private Stock<Food> foodStock;
    private Stock<Drink> drinkStock;

    public Store() {
        this.foodStock = new Stock<>();
        this.drinkStock = new Stock<>();
    }

    public Store(Stock<Food> foodStock, Stock<Drink> drinkStock) {
        this.foodStock = foodStock;
        this.drinkStock = drinkStock;
    }

    public void addItemToStock(AbstractEdible product) {
        if (product instanceof Food) {
            this.foodStock.addItem((Food) product);
        } else if (product instanceof Drink) {
            this.drinkStock.addItem((Drink) product);
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM