【问题标题】:How to use subtype polymorphism & generics for lists?如何对列表使用子类型多态性和泛型?
【发布时间】:2019-03-27 03:22:52
【问题描述】:

我正在学习 Java,并阅读了有关继承和子类型多态性的内容。现在我才刚刚开始学习泛型,我正在尝试将各个部分组合在一起,但被卡住了。

假设我有一个abstract 父类AbstractEdibles,并且有两个子类extend 来自它:FoodDrink。另外,我有一个Store,它有两个Lists:一个用于存储Food,一个用于存储Drink

现在,我希望我的 Store 能够有行为,例如添加其股票。 我想要的方法是定义一种方法来接收产品并将其放入适当的列表中。如果是Food 类型,则将其放入食物列表中。如果是Drink 类型,则将其放入酒水单中。

我确定我需要使用泛型和子类型多态性。这是我的代码的 sn-p:

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);
    }
  }
}

这不会产生错误,但我对我对类型的松散感到不满,我认为它可以变得更优化。

首先,我希望我的列表允许特定类型的edible。也就是说,foodStock 将只允许添加Food,而drinkStock 将只允许添加Drink。我尝试的是:

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

在我的 IDE 中给我一个红色下划线。于是我改成了:

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

这可行,但是我的addItemToStock() 方法抱怨我尝试添加的edibleEdible 类型,并且不能添加到包含Food 类型的List。 (这是意料之中的,因为EdibleFood 的父级;即不是每个Edible 都是Food,但每个Food 都是Edible。)

向上/向下转换 edible 也无济于事。然后我认为Upper Bounded Wildcards 是我正在寻找的东西,但这也没有用。

除此之外,我还不确定使用instanceof 是否是对对象进行分类/排序的最佳方式。

我在这里缺少什么?我不明白什么概念?

【问题讨论】:

    标签: generics inheritance java-8


    【解决方案1】:

    如果您想确保foodStock 仅存储FooddrinkStock 仅存储Drink,那么您必须像这样初始化您的列表:

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

    如果它们来自构造函数,只需声明它们:

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

    然后在构造函数中赋值:

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

    一旦你使用了instanceOf,就可以安全地使用强制转换了:

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

    您还可以创建一个通用的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;
        }
    }
    

    并在您的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);
            }
        }
    }
    

    【讨论】:

    • 嗯,显然我第一次很接近。我试过铸造,但我想我第一次没有正确地做到这一点,因为它不起作用。但是您的(第一种)方法有效,谢谢。并且 +1 还包括第二种方法。
    猜你喜欢
    • 2011-07-10
    • 2023-03-29
    • 1970-01-01
    • 2023-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多