18

For example (and this is very simplified), suppose I have a class for every card in a deck of cards... e.g. a KingOfSpaces class, a QueenOfSpades class, a JackOfDiamonds class, etc. All of which that extend Card. There might be multiple instances of KingOfSpaces.

And I have an ArrayList<Card>, with 5 objects in it. How can I check to see if that ArrayList contains at least one AceOfDiamonds?

Jasper
  • 2,166
  • 4
  • 30
  • 50
Philihp Busby
  • 4,389
  • 4
  • 23
  • 19

8 Answers8

17

Let's start out by pointing out that using classes for this sort of differentiation is almost certainly a bad thing. I'd say that you probably need to make 'Card' be a bit more intelligent (i.e. having a getSuit() and getOrdinal() method).

But, if you insist on doing it that way, iterate the array list (you can google that - it's a pretty basic thing) and compare each entry in the list using the instanceof operator.

You tagged this question as having to do with 'reflection', which doesn't seem right. Are you sure you didn't mean to flag it 'homework' ?

OK - what the heck, here's the code:

List<Card> hand = ...;
for(Card card : hand){
  if (card instanceof AceOfDiamonds) return true;
}

but please don't set up your class hierarchy like that - it's horrible design.

Kevin Day
  • 16,067
  • 8
  • 44
  • 68
  • I'm sure it's not homework... I finished my degree 5 years ago :) I guess that's what I was looking for. I was thinking there might be something more succinct like Arrays.containsInstanceOf(hand, AceOfDiamonds.class), but I suppose not. The more in-depth reason I am doing it like this is because the cards, rather than being like playing cards, are more like Magic: The Gathering cards, where each card has an special ability that modifies the "table" in some way. And like Magic, new cards may need to be added later. – Philihp Busby Nov 03 '11 at 18:39
11

Now you can do this with streams in a really simply, one-liner way:

List<Card> myList = fillitSomehow();
myList.stream().anyMatch(c -> c instanceof AceOfDiamonds);
Carrol
  • 1,225
  • 1
  • 16
  • 29
6

@Daniel Pereira answers the question as asked. I'd like to propose that what you really want is an enum.

Examples:

enum Card {
    KingOfSpades,
    QueenOfSpades,
    JackOfSpades,
    // etc
    AceOfDiamonds;
}

Card myCard = ...;
if(myCard == Card.KingOfSpades) {
    // stuff
}

Set<Card> cards = new EnumSet<Card>(Card.class);
cards.add(...);
if(cards.contains(myCard)) {
   // stuff
}
Brendan Long
  • 53,280
  • 21
  • 146
  • 188
4

Try the instanceof operator:

if (myObject instanceof myType) {
    System.out.println("myObject is an instance of myType!");
}
Daniel Pereira
  • 1,785
  • 12
  • 10
1

you can extend List like this:

public class XList<T> extends ArrayList {

    public boolean hasInstanceOf(Object obj) {
        for (Class<?extends Object> item: (Collection<Class<? extends Object>>)this ) {
            if (item.isInstance(obj)) return true;
        }
        return false;
    }

}

this solution allows you, that you can check for types dynamically instead of only static types.

you can implement the List like that:

xList<Class> classTypes = new xList<Class>();
if (classTypes.hasInstanceOf(item.getClass())){
    return true;
}
0
public static <E> boolean containsInstance(List<E> list, Class<? extends E> clazz) {
    for (E e : list) {

        try {
            List<E> list2 = (List<E>) e;
            for (E list21 : list2) {
                System.out.println("<< ENCONTRO LISTA DENTRO DEL ARRAY DE OBJETOS >> ");
                if (clazz.isInstance(list21)) {
                    return true;
                }
            }
        } catch (Exception q) {
            System.out.println("<< ENCONTRO OBJETO DENTRO DEL ARRAY DE OBJETOS >> ");
            if (clazz.isInstance(e)) {
                return true;
            }
            continue;
        }

    }
    return false;
}
  • 3
    Could you also please explain your answer so that it would be helpful for the future readers. – Prudhvi Jul 28 '15 at 14:51
0

You can use following code:

private boolean findInstance(ArrayList items, String className) {
    boolean tag = false;
    for (int i = 0; i < items.size(); i++) {
        if (items.get(i).getClass().getName().equals(className)) {
            tag = true;
            break;
        }
    }
    return tag;
}

'className' includes package name, for example: 'java.lang.String'

Tran Dinh Thoai
  • 712
  • 1
  • 7
  • 21
  • 2
    this general approach will work (kind of), but it's horribly inefficient. The instanceof operator is there for a reason. Also, your implementation could be significantly improved by returning true instead of setting tag=true. – Kevin Day Oct 12 '11 at 03:13
  • You'll really wanna be careful with this method. There's no sense of type safety, you could be having bad performance by not using iterators, and I can't be sure what will happen with the Class's getName() method. I think the other approaches listed are a bit more clear. – pseudoramble Oct 12 '11 at 03:16
  • @KevinDay while you are right getclass same is ridiculous setting tag is better then returning from multiple places. – Shahzeb Oct 12 '11 at 03:19
  • 1
    Why are you comparing classes using its name rather than the class itself? – Steve Kuo Oct 12 '11 at 04:15
  • 1
    @shahzeb - are you saying that a break statement is better than a return statement? Sorry, but no - I totally disagree with that. return is a very clear indication of intent, and is absolutely appropriate. In fact, the inclusion of the 'tag' variable is unnecessary and clutters the code - just return true if found, return false otherwise. – Kevin Day Oct 16 '11 at 02:19
  • @KevinDay we then agree to disagree :) – Shahzeb Oct 17 '11 at 22:47
0

Checking the type of an object essentially breaks various object oriented principles. The question you may want to answer is that what do you plan to do once you find that type of object.

The action to be performed would be the verb which has to be modeled for each type. For example in a game of Solitaire when you click on a card you can put it on the stack on the right if it is an Ace. So that ability whether a card can land on the stack is determined by the object itself as it knows its identity. So essentially you have to implement a deal() method to each card and based on what the object it , it knows how the deal() has to be implemented for its instance. By doing it outside the object (and checking the type) you have essentially broken encapsulation.

vivekv
  • 2,238
  • 3
  • 23
  • 37