Abstract classes in Java need definition?

Started by
7 comments, last by Fred304 18 years ago
Must abstract classes define methods which their superclasses intend to use? For example, I have two classes, Card and NumericCard. Card is abstract with 2 variables, neither of which are abstract, and no methods. NumericCard extends Card and (should) add four methods, get/set suit/value, respectively. In my main method, I instantiate a NumericCard object like this: Card card = new NumericCard(); and it compiles fine. The problem is that it doesn't recognize my get and set methods as existing. However, if I go to my Card class and declare an abstract method get/set, my main method compile and work properly. That makes me wonder: how do I add a method to my NumericCard class without adding that same abstract method to my Card class? Or am I doing something wrong? Thanks, I hope I got my question across in a clear manner. I'd be glad to clear something up if I didn't, though.
Dat is off da hizzle fo shizzle dizzle
Advertisement
Quote:Original post by The Orange Peanut
Must abstract classes define methods which their superclasses intend to use? For example, I have two classes, Card and NumericCard. Card is abstract with 2 variables, neither of which are abstract, and no methods. NumericCard extends Card and (should) add four methods, get/set suit/value, respectively. In my main method, I instantiate a NumericCard object like this:

Card card = new NumericCard();

and it compiles fine. The problem is that it doesn't recognize my get and set methods as existing. However, if I go to my Card class and declare an abstract method get/set, my main method compile and work properly. That makes me wonder: how do I add a method to my NumericCard class without adding that same abstract method to my Card class? Or am I doing something wrong?

Thanks, I hope I got my question across in a clear manner. I'd be glad to clear something up if I didn't, though.


You can add them, but then you need to declare them as NumericCard, and not Card. If you have a reference to a Card, you can only call Card methods.

NumericCard card = new NumericCard();

should allow you to call the methods that aren't in Card.
I teleported home one night; With Ron and Sid and Meg; Ron stole Meggie's heart away; And I got Sydney's leg. <> I'm blogging, emo style
Quote:Original post by jfclavette

If you have a reference to a Card, you can only call Card methods.

NumericCard card = new NumericCard();

should allow you to call the methods that aren't in Card.


Yes, I tried that and it worked, but I think it might defeat the purpose of what I was trying to do. My intent was to have a collection of Card objects (which is more than likely going to be a vector) that is filled with NumericCard objects and RoyalCard objects (also extended from Card). Isn't that what polymorphism is about?

Dat is off da hizzle fo shizzle dizzle
Quote:Original post by The Orange Peanut
Quote:Original post by jfclavette

If you have a reference to a Card, you can only call Card methods.

NumericCard card = new NumericCard();

should allow you to call the methods that aren't in Card.


Yes, I tried that and it worked, but I think it might defeat the purpose of what I was trying to do. My intent was to have a collection of Card objects (which is more than likely going to be a vector) that is filled with NumericCard objects and RoyalCard objects (also extended from Card). Isn't that what polymorphism is about?


Yes, polymorphism is about providing different level of abstractions for a type hierarchy and to permit to implement different way to respond to messages (method call) of a general group of object without caring about the gritty details of each particular object.

In that case, when you go trough your array, how the hell will you know wether your card supports a certain method ? If all card types support a method, it goes in the general card class (You can add it only as an abstract method and provide two different implementations for the different card types). If it's a method specific to a certain type, it goes in the subclass. But then, when you are treating the deck as a whole, you have to hold back to the level of abstractions that all the cards support, hence the methods declared in Card.
I teleported home one night; With Ron and Sid and Meg; Ron stole Meggie's heart away; And I got Sydney's leg. <> I'm blogging, emo style
First, ask yourself why a NumericCard would be able to do things that a RoyalCard couldn't, or vice-versa. Then, understand that, given something that you only *know* is a Card, that it is unreasonable to expect to do either NumericCard- or RoyalCard-specific things with it. What if it turned out to be the other kind?

In general (trying to keep this principle language-agnostic too), you don't want to put derived classes into a container and then try to use their specific interfaces. The polymorphism is useful here only for varying the implementation of the common interface. The container can't "remember" the types, and *if* you can statically prove the exact type of each element, all the time, then it's almost certain that you don't really have any good reason for putting them in the *same* container.

Then, ask yourself why the two would even do things in a different *way*. Why are you creating this inheritance hierarchy at all?
Quote:Original post by The Orange Peanut
Card is abstract with 2 variables, neither of which are abstract, and no methods.

Did you create the abstract Card class just to save some typing? So you do not have to declare the 2 variables in both subclasses? I would not recommend that. I even fear you might have declared them as public ;)

If you really need the distinction between a NumericCard and RoyalCard, declare an interface Card with all the relevant operations and have the two classes implements them as methods.
public interface Card{    void foo(int x);    boolean bar();}public class NumericCard implements Card{    private int a, b; // the two fields you mentioned    public void foo(int x)    {        // NumericCard implementation of foo    }    public boolean bar()    {        boolean result;        // NumericCard implementation of bar        return result;    }}public class RoyalCard implements Card{    private int a, b; // the two fields you mentioned    public void foo(int x)    {        // RoyalCard implementation of foo    }    public boolean bar()    {        boolean result;        // RoyalCard implementation of bar        return result;    }}

Well, the idea was that NumericCard would add nothing to Card except the get and set methods, and override the toString method which would return a string in the form value + " of " + suit. Then RoyalCard would add another variable, name, that would indicate if it was a king, jack, queen, or whatever since they all have the same value and the toString overrided method would instead be implemented as returning name + " of " + suit.

Anyway, I see what you are saying about the generic class needing the declarations for both classes. Though, I think I should, like another poster said, use interfaces instead. Thanks again, all of you.
Dat is off da hizzle fo shizzle dizzle
Quote:Original post by The Orange Peanut
Well, the idea was that NumericCard would add nothing to Card except the get and set methods, and override the toString method which would return a string in the form value + " of " + suit. Then RoyalCard would add another variable, name, that would indicate if it was a king, jack, queen, or whatever since they all have the same value and the toString overrided method would instead be implemented as returning name + " of " + suit.


In both cases you do provide basically the same toString: some identifier for the rank + " of " + suit. You don't need to store "names" for RoyalCards. Instead, store the value - for example, 1 for ace, 11 for jack, 12 for queen, 13 for king - and *decode* that value in the toString(). The same method works just fine for the NumericCards. You could for example just hold a static table with the rank names, and use the rank to index in (although in that case you will want the numeric "rank values" to start at 0, so a bit of arithmetic may be needed).

And why would you be able to get or set a NumericCard but not a RoyalCard?
Quote:Original post by The Orange Peanut
override the toString method which would return a string in the form value + " of " + suit.

Give enumerations a try!

public enum Suit{	DIAMONDS,	HEARTS,	SPADES,	CLUBS;		public String toString()	{		return super.toString().toLowerCase();	}}public enum Rank{	TWO (2, "2"),	THREE (3, "3"),	FOUR (4, "4"),	FIVE (5, "5"),	SIX (6, "6"),	SEVEN (7, "7"),	EIGHT (8, "8"),	NINE (9, "9"),	TEN (10, "10"),	JACK (1, "jack"),	QUEEN (1, "queen"),	KING (1, "king"),	ACE (1, "ace");	private int _value;	private String _name;		private Rank(int value, String name)	{		_value = value;		_name = name;	}	public int getValue()	{		return _value;	}		public String toString()	{		return _name;	}}public class Card{	private Rank _rank;	private Suit _suit;	private String _string;		public Card(Rank rank, Suit suit)	{		_rank = rank;		_suit = suit;		_string = _rank + " of " + _suit;	}		public Rank getRank()	{		return _rank;	}		public Suit getSuit()	{		return _suit;	}		public int getValue()	{		return _rank.getValue();	}		public String toString()	{		return _string;	}}public class Test{		public static void main(String[] args)	{		Card card = new Card(Rank.ACE, Suit.SPADES);		System.out.print("the only card you need is the " + card);	}}

This topic is closed to new replies.

Advertisement