Casting between ArrayLists in Java

42,032

Solution 1

If I understand you correctly, you should probably declare:

public class ZoneList<T extends Card> {
   protected List<T> cardBox;
}

public class PokerHand extends ZoneList<PokerCard> {
   public PokerHand() {
      cardBox = new ArrayList<PokerCard>();
   }
}

Solution 2

Marc and kolstae have given good answers in terms of how to get around the problem, but I think it's worth explaining why your original code doesn't work.

To simplify matters, I tend to put the problem in terms of fruit. Suppose we have:

List<Banana> bananaBunch = new ArrayList<Banana>();
List<Fruit> fruitBowl = bananBunch;
fruitBowl.add(new Apple());

If this is allowed, we end up with an apple in a bunch of bananas, which is obviously a bad thing. So, where is the problem? The first line has to be okay, and the third line has to be okay - you can add any kind of fruit to List<Fruit> - so the problem has to be in the second line. That's what's prohibited, precisely to avoid this kind of issue.

Does that help at all?

Solution 3

First of all, it's usually better practice to use getter/setter methods than accessing properties directly, especially if you're going to be doing a lot of complicated inheritance.

As for the generics problem, you could try defining the cardBox getter in the superclass (or top-level interface/abstract class) as:

protected ArrayList<? extends Card> getCardBox();

That way you can ovverride it in subclasses and have them return a list of any type of subclass of Card.

Solution 4

One way to do that is by casting to ArrayList first:

ArrayList<Card> cards = (ArrayList<Card>)(ArrayList<?>) (pokerCardObjects);

Another alternatives without casting:

With streams:

ArrayList<Card> cards = pokerCardObjects.stream().collect(Collectors.toCollection(ArrayList::new);

Or creating a new ArrayList:

ArrayList<Card> cards = new ArrayList<>(pokerCardObjects);

Solution 5

As stated, you cannot cast ArrayList<PokerCard> to ArrayList<Card>, but you can cast ArrayList<PokerCard> to ArrayList<? extends Card>. Or better use List<? extends Card> as your return value, because you probably don't rely on the ArrayList implementation anyway:

protected ArrayList<? extends Card> getCardBox();

As for your question in the comment, the construction should work as you described: List<? extends Card> list = new ArrayList<Card>();. You probably have to fill your list, so the method is probably something like this:

protected ArrayList<? extends Card> getCardBox() {
    List<Card> list = new ArrayList<Card>();
    list.add(pokerCard1);
    list.add(pokerCard2);
    return java.util.Collections.unmodifiableList(list);
}
Share:
42,032
user2918201
Author by

user2918201

In August of 2008 I became curious about Ruby and took up programming as a hobby. Since then I have become curious about a lot of other things, and my aspirations have quickly expanded. I very much enjoy programming, and the open source phenomenon strikes me as a window into a sustainable future. I hope that in a few years I will be able to join the scene and contribute to that future. My dreams and ambitions have been multiplied! In 2009 I decided that I would, at the age of 26, return to university and get a degree in computer science. To that end I began studying math, something I had never done before. In summer of 2010 I enrolled in a college and began taking first year computer science courses. By this time I was completely roped in by the beauty of programming. At the time I hoped to be able to transfer to a university by summer of 2011 and receive my first degree in 2014. Rather than transferring to a university, though, I took on an internship. A friend I had met through Elysian coffee, my part time job, offered to take me on as his intern in the spring of 2011 while I was taking courses. This internship turned full time during the summer, and I worked on a number of Rails and Mac projects, mostly in ruby. My love of Ruby increased tenfold, as did my understanding of the programmer's ecosystem. University transfer was pushed back to the summer of 2012, but my goal was still to graduate in 2014. Having worked with a freelance programmer for some time, I decided that after graduating, but before entering the workforce, I would dedicate some time to personal projects. At about the time these thoughts occurred to me I became aware that Canada had established a working holiday visa treaty with Taiwan. I resolved to take advantage of this unique opportunity, and to spend the end of 2014 (the year I would turn 30) and the beginning of 2015 in Taiwan as a master-less programmer. Ultimately I would like to use computer science to help "save the world". Once I have learned enough, I hope to be able to dedicate myself to whatever desperately needs doing. Whether that be related to energy, or poverty, or space travel, I want to be there with those people computing what they need computed.

Updated on August 05, 2022

Comments

  • user2918201
    user2918201 almost 2 years

    Sorry, I thought this was an inheritance question: it was an ArrayList question all along!

    Ok, my problem is more specific than I thought. So I have two families of classes. Cards, and Zones. Zones are boxes for holding card.

    The first two subClasses of Zone, ZoneList and ZoneMap are meant to be two different ways of storing Cards. Further subclasses, such as Hand, and PokerHand, have their own specific ways of dealing with the cards they store.

    Where it gets complicated is that Card also has subClasses, such as PokerCard, and that the subclasses of ZoneList and ZoneMap are meant to organize those.

    So in ZoneList I have protected ArrayList<Card> cardBox; and in PokerHand I expected to be able to declare cardBox = new ArrayList<PokerCard>(); since PokerCard is a Card. The error I am getting is that I apparently can't cast between Card and GangCard when it comes to ArrayLists... So I was trying to fix this by just redeclaring cardBox as private ArrayList<PokerCard> cardBox; inside PokerHand, but that resulted in the hiding that was bugging up my program.

    SO really, the question is about casting between ArrayLists? Java tells me I can't, so any ideas on how I can?

    z.

  • user2918201
    user2918201 over 15 years
    Ah! I didn't know I could do that: that's great! Thanks!
  • user2918201
    user2918201 over 15 years
    Oh man! That's great too. I've totally been thinking "wouldn't it be great if I knew how to pass types as parameters..." and now I totally do! Friend!
  • Jon Skeet
    Jon Skeet over 15 years
    I don't think it's an access control issue - it's a generic variance issue.
  • Jon Skeet
    Jon Skeet over 15 years
    If you're going to make ZoneList generic, you can initialize cardBox in ZoneList: List<T> cardBox = new ArrayList<T>();
  • user2918201
    user2918201 over 15 years
    When using this <? extends Card> thingy, how should I go about initializing the ArrayLists? just plain old box = new ArrayList<Card>(); returns me an error?...
  • boutta
    boutta over 15 years
    In the subclass you would instantiate a List as a property with 'private final List<PokerCard> cardBox = new ArrayList<PokerCard>()' this list would be returned by the getCardBox method.