0

I have CardType1 and CardType2 that extends Card, and an Area that has an ArrayList of Card. This array will be filled with CardType1 and CardType2 objects, but I need to eventually access them like:

for (CardType1 card : this.cards) { ...

An overview:

public class Area {

    List<Card> cards = new ArrayList<Card>();
    ..
}

public class Card {..}

public class CardType1 extends Card {..}

public class CardType2 extends Card {..}

How can I iterate over only one of the subtypes in my List<Card> cards list?

5
  • 2
    good so far, and what is the question? Commented Oct 29, 2012 at 23:18
  • Where do you need access like that? If it doesn't make sense to have a heterogeneous list than don't have one. Commented Oct 29, 2012 at 23:22
  • 1
    Thinking a little outside the box, you could partition your arraylist in such a way that you additionally store a pivot element, and keep everything before that element of type CardType1 and everything after it of CardType2. This will require some sorting and updating the arraylist on each insert and remove operation though, but it will save you the time of iterating over the elements you dont want. Commented Oct 29, 2012 at 23:29
  • That's a good solution @G.Bach since it avoids instanceof and isAssignableFrom calls. Commented Oct 29, 2012 at 23:33
  • @Brian it does, I actually don't know if those operators are slow, though. It also avoids iterating over elements he doesn't actually want to process. Whether it's a suitable solution for him will depend on whether he makes frequent changes to the arraylist or whether the number of iterations over a specific type of card is large. Commented Oct 29, 2012 at 23:36

4 Answers 4

3

You cannot do it this way, because the type of object in cards, is Card, not CardType1:

for(CardType1 card : this.cards){ ...

You can however do this:

for(Card card : this.cards) {
    if (card instanceof CardType1) {
        CardType1 card1 = (CardType1) card;
        // do something with the card1
    } else {
        CardType2 card2 = (CardType2) card;
        // do something with the card2
    }
 }

What I am doing here, is iterating through the cards, as you were (except my type is the most general type to both besides Object). Then I check if the card is of type CardType1, or CardType2, using the instanceOf operator and cast it to that type, then handle it.

Sign up to request clarification or add additional context in comments.

Comments

2

You will only be able to iterate through each item as a Card. If you were able to iterate using CardType1 then you would have an error when you encountered a card of type CardType2.

For what you want you will have to check whether card is an instance of CardType1 or CardType2 and then cast card appropriately:

for (Card card : this.cards) {
    if (card instanceof CardType1) {
        CardType1 cardType1 = (CardType1) card;
        // do something with cardType1
    }
    else if (card instanceof CardType2) {
        CardType2 cardType2 = (CardType2) card;
        // do something with cardType2
    }
}

Comments

2

The answers by Dominic and Nathan are on the mark. If you're using Guava, you can use Iterables.filter(Iterable, Class) as a shortcut:

for (CardType1 card : Iterables.filter(cards, CardType1.class)) {
    ...
}

From the documentation:

Returns all instances of class type in unfiltered. The returned iterable has elements whose class is type or a subclass of type.

3 Comments

Nice, but does this call filter on every iteration? My java is rusty.
+1, and it only calls filter once for the whole iterator, but filter will essentially call instanceof on every member of the given iterator. Guava is a must for any sufficiently complex project :)
@DominicBou-Samra Not sure I understand your question - the call delegates to Iterators.filter which returns a custom Iterator that skips elements not assignable to the type. (source)
0
ArrayList<Card> cards = new ArrayList<>();
cards.add(new CardType1());
cards.add(new CardType2());

for(Card card : this.cards){ 
   // card can be any thing that extends Card. i.e., CardType1, CardType2
   if(card instanceOf CardType1){
       //do cardType1 things
    }
   else if(card instanceof CardType2){
      // do CardType2 things
      }


}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.