Patrick Flynn
Patrick Flynn

Reputation: 13

How can I call a method on an object that is stored in a polymorphic array in Java?

Hi and thanks for taking time to look at my problem.

I am trying to call a method on an object held in an object array.

There are three classes: Cards, Guard and Deck.

The Guard class extends the Cards class.

The array is of type 'Cards' and is instantiated in the Deck class.

The Cards class is pretty much empty:

public class Cards  {
}

The object being stored in the array is of type Guard. Here is the Guard class and it's state and methods:

public class Guard extends Cards{

    private int cardScore = 2;
    private String cardName = "Guard";
    private String cardAbility = "this is the guard's ability";

    public void printGuardInfo()
    {
        System.out.println("This card score fo the guard is:      "+cardScore);
        System.out.println("The card name is: "+ cardName);
        System.out.println("The card ability is" + cardAbility);
    }
}

I am instantiating the array in the Deck class. I am then filling a array of type Cards with objects of type Guard.This is polymorphism, I believe.

This works and I can print the reference variables held at each index point.

public class Deck {
    Cards[] deck = new Cards[16];

    public Cards[] getDeck() {
        return deck;
    }

    public void addGuards()
    {
        for(int i=0; i<5; i++)
        {
            deck[i] = new Guard();
            deck[i].printGuardInfo();// Error: cannot resolve method     printGuardInfo()
        }
    }  
}

My problem is that I now cannot call the printGuardInfo() method on deck[i].

I have searched and googled for a while now but with no success. I feel like I need an interface, or abstract class of some sort. Unfortunately I am not knowledgeable enough in these areas.

Any help at all is much appreciated, Thank you.

Upvotes: 1

Views: 114

Answers (5)

SomeJavaGuy
SomeJavaGuy

Reputation: 7347

I´d promote something like this:

Make Cards an interface

public interface Cards  {
    void print();
}

Make Guard implement this interface and override the print method there with the needed information.

public class Guard implements Cards{
    // ... Other methods and stuff
    @Override
    public void print() {
        System.out.println("This card score fo the guard is:      "+cardScore);
        System.out.println("The card name is: "+ cardName);
        System.out.println("The card ability is" + cardAbility);
    }
    // ... Other methods and stuff
}

Now in the loop you just have to call

deck[i].print();

What is getting printed now will be depending on the actual implementation of what has to be printed, but in generall the class Cards will know that it can print now.

Edit: Following @chrylis comment, your class should be called Card instead of Cards. The reason here? It´s like a simple plan for a single type of Card(class here), but doesn´t represent multiple Cards(multiple cards would be instances of Card).

Upvotes: 5

Massimo Petrus
Massimo Petrus

Reputation: 1891

R2-D2 is right, but if you want to be more 'polymorphic' you should do something like This

public interface ICard {
    public void printInfo();

}

public class Card implements ICard{

  public void printInfo(
    System.out.println("Card Info");
  }
}

public class Guard extends Card {

   public void printInfo{
        System.out.println("GUARD Info");
 }
}


public vlass Deck{
...
public void addGuards()
{
        for(int i=0; i<5; i++)
        {
          deck[i] = new Guard();
          deck[i].printInfo();
        }
    }  

}

Or even use an abstract class

Upvotes: 2

Mena
Mena

Reputation: 48404

While some of the proposed solutions make sense in the narrow case (using a combination of instanceof and casting the impacted Cards element to Guard in order to invoke printGuardInfo), there might be a broader problem with the design of your inheritance.

Assuming Cards is not really an empty class (otherwise the hierarchy does really not produce any benefit), my advice is to group your card objects under a common interface or abstract class (say, Card), and have that interface provide an abstraction for general methods such as printInfo, which is then implemented by each Card type (you'd get the printGuardInfo code inside the Guard implementation there).

In turn, when iterating your array, you'd invoke printInfo on each card, knowing that each and every child of Card has its own printInfo implementation, without the need to cast or use instanceof.

Upvotes: 3

Steve Chaloner
Steve Chaloner

Reputation: 8202

The easiest, most object-oriented way to do this is to change printGuardInfo to toString:

public String toString()
{
    return new StringBuilder("This card score fo the guard is:      ")
                  .append(cardScore).append('\n')
                  .append("The card name is: ")
                  .append(cardName).append('\n')
                  .append("The card ability is ")
                  .append(cardAbility)
                  .toString();
}

You can then call String guardInfo = deck[i].toString(); to get the guard info and write it to standard output, a logger, etc.

public String toString() is inherited from Object, so no casting is needed to call it.

Upvotes: 2

R2-D2
R2-D2

Reputation: 1624

You need to cast the Card to a Guard:

((Guard) deck[i]).printGuardInfo();

Upvotes: 2

Related Questions