views:

2197

answers:

5

Hi

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.

+1  A: 

This is going to depend on what the access control is on the Arraylist in Zonelist. My assumption from the debugger statement is that it is either unmarked, public, or protected. A subclass can "Hide" a parent class' variable it has access to by defining a variable with the same name. You can also use this keyword to refer to the particular object instance and super keyword to refer to the parent.

Here is a good link on basic access control in Java:

http://java.sun.com/docs/books/tutorial/java/javaOO/accesscontrol.html

This you might also find helpful

http://java.sys-con.com/node/46344

Scanningcrew
I don't think it's an access control issue - it's a generic variance issue.
Jon Skeet
+5  A: 

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.

Marc Novakowski
Ah! I didn't know I could do that: that's great! Thanks!
Ziggy
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?...
Ziggy
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.
boutta
+2  A: 

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>();
   }
}
refrus
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!
Ziggy
If you're going to make ZoneList generic, you can initialize cardBox in ZoneList: List<T> cardBox = new ArrayList<T>();
Jon Skeet
+4  A: 

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?

Jon Skeet
+2  A: 

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);
}
Markus
This helped a lot, thanks.
DutrowLLC