Objects and Classes



[When asked] "...why is it called a class?" ... I reply "Because that's the place where we teach objects how to do things".
    -Rich Pattis






A class is a blueprint for a collection of objects. A class describes a collection of objects that have similar attributes and behaviors.



Example: Dog is a real-world class

Every class has associated data, or attributes.
Attributes for Dog class: breed, color, height, weight, gender, name

Every class has associated actions.
Actions for Dog class: bark, sleep, eat

Instances of the Dog class, or objects in the Dog class:
my dog Otis, your dog, former president Bill Clinton's dog Buddy


If we translate the Dog class into a Java class, we get this:

class Dog
{
   ...
    String breed;
    String name;
    double height;
    double weight;
    char gender;

    // In order to be able to create specific Dog instances, or objects of type Dog, we need
    // a method (a constructor) that creates an instance:
    public Dog(String theName, char theGender)
    {
        name = theName;
        gender = theGender;
    }

    public void bark()
    {
        System.out.println("Rff, rff");
    }

    public void sleep()
    {
       System.out.println("zzzz, zzzz");
    }

    public void eat()
    {
        System.out.println("slurp");
    }
} // end of Dog class


Now if I'm writing a program, I can create a Dog object:

Dog otis = new Dog("Otis", 'm');  // this object is a software representation of my dog
                                                   // Otis




I can call the methods that were defined in the Dog class on my Dog instance:

otis.bark(); // output to screen: Rff, rff





To create an instance of any class: Use the new operator and invoke the constructor.
new ClassName(... any needed arguments...)


to assign the address of this new object to a reference variable of type ClassName:


ClassName myRefVar = new ClassName(arguments);


The use of the new keyword causes the creation, or construction, of a new object. The object is an instance of the specified class. When new is used, a constructor for the class is called.





Defining Methods


A method definition contains:

1. An access specifier (like public)
       -- determines which other methods can call your method
       -- most methods are declared public, so that all other methods in your program can
          call them
2. The return type of the method (like void - which means no value is returned - or int, String, etc)
       -- some methods return a value
                Ex: The method Character.isDigit() returns a boolean value
       -- a return type of void means that the method executes some statements without
          returning a value
3. The name of the method (such as bark)
4. A list of the parameters of the method, enclosed in parentheses (our Dog constructor takes the parameters theName, theGender)
       -- some methods take in other information
       -- the constructor for Dog takes the Dog's name and gender, and uses those values
          in the body of the method
5. The body of the method, which is enclosed in curly braces - a sequence of statements



Syntax:
class ClassName
{
   ....
    accessSpecifier returnType methodName (parameterType parameterName, ... )
    {
        method body
    }
    ...
}




Ex:
public class Speaker
{
    ...
    public String sayHi()
    {
        String message = "Hello Friend";
        return message;  // this method returns to the caller a reference to the String message
    }
}



Note: A method's execution ends when a return statement is executed. The return value becomes the value of the method call expression.


What can we do with our Speaker class? We can compile it. But we cannot run it, because it does not contain a main method. So we write a test class - a class with a main method that allows us to try out the Speaker class.



Ex:
public class SpeakerTest
{
    public static void main(String[] args)
    {
        // Create a new Speaker
        Speaker friendly = new Speaker();
        System.out.println(friendly.sayHi());
    }
}



So your program consists of these 2 classes. To run your program, you:
1. Make a subfolder for your program.
2. Make two files, one per class.
3. Compile both files.
4. Run the test program.






Defining Instance Fields



Let's add some data to our Speaker class:

public class Speaker
{
    private String name; // the name of the person to speak to

    public String sayHi()
    {
       String message = "Hi " + name;
       return message;
    }
}



An instance field contains:
1. Acess specifier (typically private)
2. Type of the variable (e.g., String, int, double)
3. Variable name




Syntax:
accessSpecifier  Type  varName;





Constructors


We now need to change our Speaker class so that we can construct Speaker objects with different names:


class Speaker
{
    public Speaker(String personName)  // a constructor for the Speaker class
    {
       name = personName;
    }

   ... // the stuff we included before
}


A constructor allows us to create instances of our class. The constructor has the same name as the class, and is typically public.


Example:
To create an instance of Speaker class:

Speaker mrFred = new Speaker("Mr. Fred");
mrFred.sayHi();  // output: Hi Mr. Fred



Example: Write a class that represents a circle. Write another class to test the Circle class.



Designing a Class

Think about the objects that will be created from the new class type. Think about:


Example: For an Alarm class - think about what an Alarm object knows and does


Example: For a Car class - think about what a Car object knows and does


Instance variables are an object's data, i.e., the things an object knows about itself.
Things an object can do are called methods.


Note: Often our classes contain methods that read or write the values of the instance variables. 




Designing A Class, Start to Finish


Example: Rectangle class

Before you start coding, think about how the objects of your class should behave. What operations should a Rectangle be capable of, for example?

               
These operations that you chose should become methods in the class.


What data do you want to store for each Rectangle object?







Example: BankAccount - write a class that represents a bank account

1. Decide what operations/methods you need

What operations do you want to carry out with a bank account?

If you have a BankAccount object called myChecking, you would like to be able to call methods like:



myChecking.deposit(2000);  // add $2000 to my checking account
myChecking.withdraw(30);   // get some cash
System.out.println(myChecking.getBalance()); // let me see my current balance


So the BankAccount class should contain the methods:

2. Figure out what information each method needs to receive (parameters), and what will be the return value, if any (what do they compute?).

In our examples, the deposit and withdraw methods took a double value, a money amount, and did not return a value. The getBalance method did not take any parameters, but returned a double value, the account balance. So we have these method headers:

public void deposit(double depositAmount)
public void withdraw(double withdrawAmount)
public double getBalance()



3. What information do we need to store about each BankAccount instance?

       We need to keep track of the bank account's balance: double balance



4. Next, let's think about the constructors - how do we want to be able to create BankAccount objects?
So we could create a BankAccount instance like this:

BankAccount myChecking = new BankAccount(); // this should create my account with a zero balance

or with this statement:

BankAccount myChecking = new BankAccount(500); // initial balance is 500

Two constructors:
When we use the same method name for multiple methods that have different parameters, we say the method name is overloaded.



The constructors and methods of a class make up the public interface of the class. These are the operations that any code in your program can call to create and alter BankAccount objects.



Ex: the public interface of the BankAccount class is

public BankAccount()
public BankAccount(double initialBalance)
public void deposit (double depositAmount)
public void withdraw(double withdrawAmount)
public double getBalance()


The behavior of our BankAccount class allows you to carry out all the common operations on bank accounts.


Example: Using some BankAccount objects (this code would not go in the BankAccount class - it might go in a class called BankAccountTest, for example)

Take $3000 from Mom's savings account and move it to my checking account:

double amt = 3000;
momSavings.withdraw(amt);
myChecking.deposit(amt);



We can use objects of the BankAccount class to manipulate money without knowing how the BankAccount objects carry out these operations. Providing the user of a class with the public interface and hiding the implementation details is called encapsulation, an important object-oriented concept.






Implementing the Class


Now that we have decided what methods and constructors we want our class to have, and how we want to use them, we need to implement them and add necessary instance fields to our class.

What data do we need to store for our bank account objects? The balance.


Example: BankAccount class definition

public class BankAccount
{
    private double balance;  // only allow access to the balance through the getBalance() method. Only the BankAccount                                             // methods and constructors can access.
                                            // The balance is a private implementation detail of this class - this is encapsulation!

    public BankAccount()  // create a bank account with a 0 balance
    {
        balance = 0;
    }

    public BankAccount(double initialBalance)  // create a bank account with the specified balance
    {
        balance = initialBalance;
    }

    public void deposit (double depositAmount)
    {
        balance += depositAmount;
    }

    public void withdraw (double withdrawAmount)
    {
        if((balance - withdrawAmount) >= 0)  // do not allow account to be overdrawn
           balance -= withdrawAmount;
    }

    public double getBalance()
    {
        return balance;
    }
}


Note: when I refer to an instance variable like balance in my code, I am referring to the balance of the current object.
  


Example: BankAccountTest class

public class BankAccountTest
{
    // This class tests the BankAccount class

    public static void main(String[] args)
    {
         BankAccount myChecking = new BankAccount();  // initial zero balance
         myChecking.deposit(2000); // deposit a check for $2000
         System.out.println("My balance is: " + myChecking.getBalance());

        BankAccount momSavings = new BankAccount (5000);
        momSavings.withdraw(2000); 
    }
}






Steps in creating a class:




Exercise: Write a class that represents a coin that can be flipped.


Exercise: Write a class to test your Coin class. This class should prompt the user to choose either heads or tails. Then it should toss a coin and tell the user if they won or not.