Кастинг между ArrayLists в Java
Вопрос
Извините, я думал, это вопрос о наследстве:все это время это был вопрос ArrayList!
Хорошо, моя проблема более конкретна, чем я думал.Итак, у меня есть две семьи классов.Карты и зоны.Зоны представляют собой ячейки для хранения карт.
Первые два подкласса Zone, ZoneList и ZoneMap предназначены для двух разных способов хранения карт.Дальнейшие подклассы, такие как Hand и PokerHand, имеют свои собственные способы обращения с хранящимися в них картами.
Сложность заключается в том, что у Card также есть подклассы, такие как PokerCard, и что подклассы ZoneList и ZoneMap предназначены для их организации.
Итак, в ZoneList у меня есть protected ArrayList<Card> cardBox;
и в PokerHand я ожидал, что смогу объявить cardBox = new ArrayList<PokerCard>();
поскольку PokerCard — это карта.Ошибка, которую я получаю, заключается в том, что я, по-видимому, не могу выполнить преобразование между Card и GangCard, когда дело доходит до ArrayLists...Поэтому я пытался это исправить, просто переобъявив cardBox как private ArrayList<PokerCard> cardBox;
внутри PokerHand, но это привело к сокрытию, которое мешало моей программе.
ТАК действительно, вопрос в кастинге между ArrayLists?Java говорит мне, что я не могу, есть идеи, как я могу?
з.
Решение
Если я вас правильно понял, вам, вероятно, следует объявить:
public class ZoneList<T extends Card> {
protected List<T> cardBox;
}
public class PokerHand extends ZoneList<PokerCard> {
public PokerHand() {
cardBox = new ArrayList<PokerCard>();
}
}
Другие советы
Марк и Колстае дали хорошие ответы о том, как обойти проблему, но я думаю, что стоит объяснить. почему ваш исходный код не работает.
Чтобы упростить ситуацию, я склонен рассматривать проблему с точки зрения фруктов.Предположим, у нас есть:
List<Banana> bananaBunch = new ArrayList<Banana>();
List<Fruit> fruitBowl = bananBunch;
fruitBowl.add(new Apple());
Если это разрешено, в связке бананов мы получим яблоко, что, очевидно, плохо.Итак, в чем проблема?Первая строка должна быть в порядке, и третья строка должна быть в порядке — вы можете добавить в нее любые фрукты. List<Fruit>
- значит, проблема должна быть во второй линии.Это то, что запрещено, именно во избежание подобных проблем.
Это вообще помогает?
Прежде всего, обычно лучше использовать методы получения/установки, чем прямой доступ к свойствам, особенно если вам предстоит выполнять много сложного наследования.
Что касается проблемы с дженериками, вы можете попробовать определить метод получения cardBox в суперклассе (или интерфейсе верхнего уровня/абстрактном классе) как:
protected ArrayList<? extends Card> getCardBox();
Таким образом, вы можете переопределить его в подклассах и заставить их возвращать список любого типа подкласса Card.
Один из способов сделать это — сначала выполнить приведение к ArrayList:
ArrayList<Card> cards = (ArrayList<Card>)(ArrayList<?>) (pokerCardObjects);
Другие альтернативы без кастинга:
С потоками:
ArrayList<Card> cards = pokerCardObjects.stream().collect(Collectors.toCollection(ArrayList::new);
Или создайте новый ArrayList:
ArrayList<Card> cards = new ArrayList<>(pokerCardObjects);
Как уже говорилось, вы не можете использовать ArrayList<PokerCard>
к ArrayList<Card>
, но вы можете применить ArrayList<PokerCard>
к ArrayList<? extends Card>
.Или лучше использовать List<? extends Card>
в качестве возвращаемого значения, потому что вы, вероятно, все равно не полагаетесь на реализацию ArrayList:
protected ArrayList<? extends Card> getCardBox();
Что касается вашего вопроса в комментарии, то конструкция должна работать так, как вы описали: List<? extends Card> list = new ArrayList<Card>();
.Вероятно, вам придется заполнить свой список, поэтому метод, вероятно, будет примерно таким:
protected ArrayList<? extends Card> getCardBox() {
List<Card> list = new ArrayList<Card>();
list.add(pokerCard1);
list.add(pokerCard2);
return java.util.Collections.unmodifiableList(list);
}
Это будет зависеть от того, какой контроль доступа установлен в Arraylist в Zonelist
.Исходя из оператора отладчика, я предполагаю, что он либо не помечен, либо общедоступен, либо защищен.Подкласс может «скрыть» переменную родительского класса, к которой у него есть доступ, определив переменную с тем же именем.Вы также можете использовать this
ключевое слово для ссылки на конкретный экземпляр объекта и super
ключевое слово для ссылки на родителя.
Вот хорошая ссылка на базовый контроль доступа в Java:
http://java.sun.com/docs/books/tutorial/java/javaOO/accesscontrol.html
Это также может оказаться вам полезным