Objects are building blocks of software systems
Program is collection of interacting objects
Objects cooperate to complete a task
Objects communicate by sending message to each other
Concepts (meeting, date)
Processes (Sorting, simulations)
Capabilities (drive, change speed, admit passenger)
Queries: Provide answer based on object's properties (e.g., how fast?)
affect how object reacts to messages
components (e.g., doors)
associations (e.g., driver)
new Card(Ace,Spades);May be used as basis for more refined classes
class PinochleCard extends CardContains info on all fields and method bodies, including non-public
    public boolean equals(Object other)
    public int hashCode()
    public String toString()
Don't need to write these in interfaces, often "override" definitions in classes.
// A playing card interface.  
// Advertises all the public features of a card object.
public interface CardInterface{
    // "final" is what makes them constants
    // "static" shares one copy of the value over all objects 
    // in class.  I.e., all objects get access to same copy
    
    // Constants
    static final int CLUBS = 0;
    static final int DIAMONDS = 1;
    static final int HEARTS = 2;
    static final int SPADES = 3;
    
    // No need to start with 0 as first value;  
    // they need not even be consecutive
    static final int TWO = 2;
    static final int THREE = 3;
    static final int FOUR = 4;
    static final int FIVE = 5;
    static final int SIX = 6;
    static final int SEVEN = 7;
    static final int EIGHT = 8;
    static final int NINE = 9;
    static final int TEN = 10;
    static final int JACK = 11;
    static final int QUEEN = 12;
    static final int KING = 13;
    static final int ACE = 14;
    // Methods
    int getSuit();
    int getRank();
}
//-------------------------------------------
// A playing card implementation
public class Card implements CardInterface
{
    // "protected" means other classes can't access them 
    //  (data hiding)
    // instance variables
    protected int suit;     // The suit of card: CLUBS..SPADES
    protected int rank;     // The rank of the card: TWO..ACE
    
    // Constructors
    
    // This version of the constructor does all of the work
    public Card(int theRank, int theSuit)
    // post:  Constructs a card of the given type
    {
        suit = theSuit;
        rank = theRank;
    }
    
    // This constructor merely invokes the two-argument 
    //  constructor, using "this" syntax
    public Card()
    // post:  Constructs card with value "Ace of Spades"
    {
        this(ACE,SPADES);
    }
    
    // Methods
    public boolean equals(Object other)
    // pre:  other is a non-null CardInterface
    // post:  returns true iff this equals other
    {
		CardInterface otherCard = (CardInterface) other;
		return (suit == otherCard.getSuit()) && (rank == otherCard.getRank());
    }
    
    // Having this method allows Cards to be used in certain 
    // data structures. For now, just try to return different 
    // values for different cards. This returns a number in the 
    // range 0..51;  different cards yield different values
    public int hashCode()
    // post:  returns hash code for this card
    {
        return 13*suit + rank - 2;
    }
    
    public int getSuit()
    // post:  returns suit of card
    {
        return suit;
    }
    
    public int getRank()
    // post:  returns rank of card
    {
        return rank;
    }
    
    // Java provides a String class with many useful methods
    // "switch" is Java's "case" statement
    // It must end each block with "break", or else next block 
    //  is also executed
    // The "default" block is optional
    protected String getSuitString()
    // post:  returns a string representation of the suit
    {
        String suitStr = null;
        switch (suit)
        {
            case CLUBS:
                suitStr = "Clubs";
                break;
            case DIAMONDS:
                suitStr = "Diamonds";
                break;
            case HEARTS:
                suitStr = "Hearts";
                break;
            case SPADES:
                suitStr = "Spades";
                break;
            default:
        }           
        return suitStr; 
    }
    
    protected String getRankString()
    // post:  returns a string representation of the rank
    {
        String rankStr = null;
        switch (rank)
        {
            case TWO:
                rankStr = "Two";
                break;
            case THREE:
                rankStr = "Three";
                break;
            case FOUR:
                rankStr = "Four";
                break;
            case FIVE:
                rankStr = "Five";
                break;
            case SIX:
                rankStr = "Six";
                break;
            case SEVEN:
                rankStr = "Seven";
                break;
            case EIGHT:
                rankStr = "Eight";
                break;
            case NINE:
                rankStr = "Nine";
                break;
            case TEN:
                rankStr = "Ten";
                break;
            case JACK:
                rankStr = "Jack";
                break;
            case QUEEN:
                rankStr = "Queen";
                break;
            case KING:
                rankStr = "King";
                break;
            case ACE:
                rankStr = "Ace";
                break;
            default:
        }           
        return rankStr; 
    }
    
    // The toString method is special.  
    // It allows for automatic printing of Objects
    // Note:  + for String concatenation
    public String toString()
    // post:  returns a string representation of this card
    {
        return getRankString() + " of " + getSuitString();
    }
    // The toString method is special.  
    // It allows for automatic printing of Objects
    // Note:  + for String concatenation
    public String toString()
    // post:  returns a string representation of this card
    {
        return getRankString() + " of " + getSuitString();
    }
    // If a class contains a main method, 
    // that method can be run when the class is compiled
    // I always have one, which I use for testing the class
    public static void main(String args[])
    // Test Card class
    {
        // Create some cards
        CardInterface first = new Card(THREE,DIAMONDS);
        CardInterface second = new Card();
        
        System.out.println();
        System.out.println(first);
        System.out.println(second);
        System.out.println();
        
        // Note:  ! is the negation operator
        System.out.print("These cards are ");
        if(!first.equals(second))
            System.out.print("not ");
        System.out.println("equal");
        System.out.println();
        
        // Create an array of cards
        // Note syntax for array declaration
        CardInterface[] hand = new CardInterface[5];
        hand[0] = new Card(ACE,HEARTS);
        hand[1] = new Card(KING,HEARTS);
        hand[2] = new Card(QUEEN,HEARTS);
        hand[3] = new Card(JACK,HEARTS);
        hand[4] = new Card(TEN,HEARTS);
        
        // for loop
        // Note: declaration in for loop; 
        // ++ is the "add 1" operator
        for(int i=0;i<4;i++)
            System.out.print(hand[i] + ", ");
        
        System.out.println(hand[4]);
    }
}