0

I am trying to add cards to a list by using their class name, then I want to call one of their methods. How can I do that? I have this for now:

Into the super class Card:

public static ArrayList<Object> CreateAllCards() throws ClassNotFoundException
    {
        ArrayList<Object> cardArray = new ArrayList<>();

        for (int n = 0; n<cardList.length; n++)
        {
            if (isCardAllowedToBeCreated[n])
            {
                Class card = Class.forName(cardList[n]);
                cardArray.add(card);
            }
        }

        return cardArray;
    }

    static String[] cardList = {
        "CrtAbyssalSpecter",
        "CrtAirElemental",
        "ArtAladdinsRing",
        "SorAmbitionsCost",
        "CrtAnabaShaman",
        "CrtAngelOfMercy",
        "CrtAngelicPage",
        //...
    };
}

Somewhere else, my main:

public static void main(String[] args) throws ClassNotFoundException {

    ArrayList<Object> cardList = Card.CreateAllCards();

    for (int n=0; n<cardList.size(); n++)
    {
        if (cardList.get(n) instanceof Creature)
        {
            // How to call a specific method?
        }
    }

}

Also, is there a way to directly create an arraylist of Card by using each card name rather than creating an arraylist of object (by each card name) like I do?

Krease
  • 15,805
  • 8
  • 54
  • 86
Mickael Bergeron Néron
  • 1,472
  • 1
  • 18
  • 31

2 Answers2

2

You are filling the list with objects that represent classes; you are not creating objects of them. To create objects call the newInstance method:

            Class card = Class.forName(cardList[n]);
            // Create object by calling the default no-arg constructor:
            cardArray.add(card.newInstance());

After that you can call specific methods by casting, like already suggested by the other answer:

    if (cardList.get(n) instanceof Creature)
    {
        Creature c = (Creature) cardList.get(n);
        c.creatureSpecificMethod();
    }

There might be a better, more flexible, object oriented approach though. Don't these "card" objects have anything in common? If they do, they should probably implement the same interface or inherit from the same super class, and checks like "if the current card is a creature card do X" could be kept to a minimum. See "Prefer Polymorphism Over InstanceOf and Downcasting."

Update:

To create a list of Cards you need these modifications: First declare the list as a list of Card:

ArrayList<Card> cardArray = new ArrayList<>();

Then use the asSubclass method to "cast" the result of forName into a subclass of Card:

Class<? extends Card> card = Class.forName(cardList[n]).asSubclass(Card.class);
cardArray.add(card.newInstance());
Joni
  • 108,737
  • 14
  • 143
  • 193
2

Using casting, like so:

public static void main(String[] args) throws ClassNotFoundException
{

    ArrayList<Object> cardList = Card.CreateAllCards();

    for(Object card : cardList)
    {
        if(card instanceof Creature)
        {
            Creature creature = (Creature) card;
            creature.creatureMethod();
        }
    }
}

Additionally I changed your for loop style to the more efficient for each.

MrLore
  • 3,759
  • 2
  • 28
  • 36
  • Isn't foreach loop slower than the normal for loop? – Sri Harsha Chilakapati Jul 20 '13 at 11:51
  • @SriHarshaChilakapati Not in this case, as before he was using `.get(int element)` every time which has O(n) efficiency, whereas foreach uses the iterator which is O(1), see this answer for more information: http://stackoverflow.com/a/2113226/1276341 – MrLore Jul 20 '13 at 11:56
  • Thanks for sharing that answer. I was taught like that in my GameDev class where we need to query a list of almost 200 objects in a while loop which loops at 30 times in a second. – Sri Harsha Chilakapati Jul 20 '13 at 11:59
  • `ArrayList.get(int)` is Θ(1) - an array lookup takes constant time. – Joni Jul 20 '13 at 12:20
  • The `CreateAllCards` method returns an array of **classes** not instances – c.s. Jul 20 '13 at 12:52