#generics #inheritance #java-8
#обобщения #наследование #java-8
Вопрос:
Я изучаю Java и прочитал о наследовании и полиморфизме подтипов. Сейчас я только начинаю изучать дженерики и пытаюсь собрать кусочки воедино, но застрял.
Допустим, у меня есть abstract
родительский класс AbstractEdibles
, и есть два дочерних, extend
происходящих от него: Food
и Drink
. Кроме того, у меня есть a, Store
у которого есть два List
s: один для хранения Food
и один для сохранения Drink
.
Теперь я хочу, чтобы мой Store
мог иметь поведение, такое как добавление к его запасу. Мой желаемый подход заключается в определении одного метода для получения продукта и помещения его в соответствующий список. Если это Food
тип, внесите его в список продуктов. Если это тип Drink
, поместите его в список напитков.
Я уверен, что мне нужно использовать дженерики и полиморфизм подтипов. Вот фрагмент моего кода:
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()
метод жалуется, что edible
я пытаюсь добавить, имеет тип Edible
и не может быть добавлен к List
содержащему типу Food
. (Это ожидаемо, потому что Edible
является родителем Food
; т.е. не каждый Edible
является Food
, но каждый Food
есть Edible
.)
Приведение вверх / вниз edible
тоже не помогает. Тогда я подумал, что подстановочные знаки с верхними границами — это то, что я искал, но это также не сработало.
Кроме того, я также не уверен, что использование instanceof
является лучшим способом классификации / сортировки объектов.
Чего я здесь не понимаю? Какую концепцию я не понимаю?
Ответ №1:
Если вы хотите гарантировать, что только foodStock
хранилища Food
и только drinkStock
stores 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. Хм, видимо, я был близок к этому в первый раз. Я попробовал кастинг, но, думаю, с первого раза я сделал это неправильно, так как это не сработало. Но ваш (первый) метод сработал, спасибо. И 1 за то, что также включен второй подход.