05. Object Oriented Programming with Java

Object

  • An object is an encapsulation of services (behavior) and attributes/data (state). Software objects are often used to model real-world objects you find in everyday life.
  • Two important characteristics of real-world objects: Have state, Have behavior
  • Software objects are modeled after real-world objects, so software objects have state and behavior. A software object maintains its state in variables and implements its behavior with methods

Classes

A class is a template or blueprint from which an object is actually made. This is similar to a C structure, but with functions. Unlike the classes we have written so far, a class for an object will contain variables for one object and methods that operate on those variables. An instance of a class is an object.

You may use a UML (Unified Modeling Language) class diagram to describe the class:

UML diagram for the Circle class:

Circle
-radius: double
-xCoord: double
-yCoord: double
+Circle( r:double, x:double, y:double) <<constructor>>
+circumference():double
+area():double
+getRadius():double
+getXCoord():double
+getYCoord():double
+setRadius(r: double)
+setXCoord(x: double)
+setYCoord(y: double)
+display()

Note: param-id : param-type may be a list

Optional before var-id or method-id: + (public), - (private), # (protected)

Optional access modifier (before class): public

  • Recall that public means class may be accessed from anywhere
  • There may be only one public class in a file
  • The name of the file must be the name of the public class (with the .java extension)
  • If NOT public (no access modifier), then the class and its members are accessible only by other classes within the same package (same directory) (more on packages later)

Class-scope Variables:

  • public variables may be accessed from any method that could access the class in which they are declared
  • private variables may be accessed only from methods inside its class (actual access may be limited)
  • static variables exist from when class is loaded to the end of the program and are called "class variables"
  • instance variables (any class-scope variable that's NOT static) exist when only when the class in which they are declared is instantiated until it's "garbage collected"

Note: Class-scope variables may be (public OR private OR none) AND (static OR not). No access specifier is package-scope

Method definitions:

  • Often include one or more constructor methods which are usually used to initialize the variables. A constructor is automatically called when a class is instantiated
  • Often include accessor methods which return the values of private variables, usually named getVarName
  • Sometimes include mutator/modifier methods which change the values of private variables, usually names setVarName
/*
Exercise 5.1: (.java document and the UML diagram) - Create a class Rectangle that has attributes (private instance variables) called length and width,  each of which defaults to 1. Include either instance variables or methods for the area and perimeter.
 - First write the UML diagram for the Rectangle class. Then write it in Java. If one or both of the parameters are <=     0, the constructor should leave or assign the default values, and the mutator should leave the length or width as it     was before.
 - Before you could test this, read page 5.7 first (not required to run this for the exercise).
*/
public class Exercise_5_1_Rectangle
{
    private double d_length = 1;
    private double d_width = 1;
   
    public Exercise_5_1_Rectangle(double length, double width)            // Constructor
    {
        // Only assign value if it is > 0 otherwise set value to 1
        d_length = (length > 0) ? length : 1;
        d_width = (width > 0) ? width : 1;
    }
   
    public double calculatePerimeter()
    {
        return 2 * (d_length + d_width);
    }   
   
    public double calculateArea()
    {
        return d_length * d_width;
    }
   
    public double getLength()
    {
        return d_length;
    }
   
    public double getWidth()
    {
        return d_width;
    }
   
    public void setLength(double length)
    {
        d_length = length;
    }
   
    public void setWidth(double width)
    {
        d_width = width;
    }
   
    public static void main(String[] args)
    {
        // Exercise 5.2
    }
}
/*
-- UML diagram
Exercise_5_1_Rectangle
-d_length: double
-d_width: double
+Exercise_5_1_Rectangle( length:double, width:double) <<constructor>>
+CalculatePerimeter():double
+CalculateArea():double
+getLength():double
+getWidth():double
+setLength(length: double)
+setWidth(width: double)
+display()
*/

Creating Java Objects

In order to create a Java object (other than a String), you need to instantiate a class.

Syntax to instantiate a class: new ClassName( initial-values )

Note that the initial-values must match in number and type of at least one of the constructors for that class

Example: new Circle(1., 3., 5.);

Declaring Object Variables:

The syntax to declare an object variable is the same as declaring a variable of a primitive type, BUT the type is a class, and ...

  • an object variable will only refer to an object (after it is assigned), but is not the whole object (unlike C++)
  • you cannot copy whole objects by assigning an object variable to another object variable

/* Exercise 5.2: Write main (may be in the same or separate class from the Rectangle class) to test the Rectangle class (in Exercise 5.1).

    Instantiate at least 2 Rectangle objects, assigning them to Rectangle variables in main.
    Call several of the instance methods in the Rectangle class on those objects, displaying the results. */
public class Exercise_5_2_Rectangle
{
    private double d_length = 1;     // Remove initialization from here, not needed
    private double d_width = 1;
  
    public Exercise_5_2_Rectangle()  // Default Constructor
    {
        d_length = 1;
        d_width = 1;
    }
   
    public Exercise_5_2_Rectangle(double length, double width)            // Constructor
    {
        // Only assign value if it is > 0 otherwise set value to 1
        d_length = (length > 0) ? length : 1;
        d_width = (width > 0) ? width : 1;
    }
   
    public double calculatePerimeter()
    {
        return 2 * (d_length + d_width);
    }   
   
    public double calculateArea()
    {
        return d_length * d_width;
    }
   
    public double getLength()
    {
        return d_length;
    }
    public double getWidth()
    {
        return d_width;
    }
    public void setLength(double length)
    {
        // d_length = length;                            // -> NOT Correct in submitted homework 5.1
        d_length = (length > 0) ? length : 1;
    }
    public void setWidth(double width)
    {
        //d_width = width;                                // -> NOT Correct in 5.1
        d_width = (width > 0) ? width : 1;
    }
    public void display(){
        System.out.println("Rectangle: length = "+ d_length + ", width = " + d_width +
            ", perimeter = "+ calculatePerimeter() + ", area = " + calculateArea());    // Only for test
  }
    public static void main(String[] args)
    {
        // Exercise 5.2
        Exercise_5_2_Rectangle oRectangle1 = new Exercise_5_2_Rectangle(5,2);
        Exercise_5_2_Rectangle oRectangle2 = new Exercise_5_2_Rectangle(0,-2);
        Exercise_5_2_Rectangle oRectangle3 = new Exercise_5_2_Rectangle();                // Default constructor
       
        // Test constructor
        oRectangle1.display();
        oRectangle2.display();
        oRectangle3.display();
       
        // test get set method
        oRectangle3.setLength(10);
        oRectangle3.setWidth(0);
        System.out.println("Rectangle3: getLength() - " + oRectangle3.getLength() + ", getWidth() - " + oRectangle3.getWidth());
        oRectangle3.display();
    }
}
/* Output:
Rectangle: length = 5.0, width = 2.0, perimeter = 14.0, area = 10.0
Rectangle: length = 1.0, width = 1.0, perimeter = 4.0, area = 1.0
Rectangle: length = 1.0, width = 1.0, perimeter = 4.0, area = 1.0
Rectangle3: getLength() - 10.0, getWidth() - 1.0
Rectangle: length = 10.0, width = 1.0, perimeter = 22.0, area = 10.0
*/

Class Features

  • this keyword refers to the object on which the method operates, for instance methods only (examples below)
  • A class may have more than one constructor or method with the same name, but eachmust be unique in its parameters (for example, differ in number of parameters and/or type of parameters). This is another example of method overloading.
  • Garbage Collection is the Java interpreter de-allocating memory for objects that have no references to them. This occurs sporadically, when "nothing else is going on" (e.g., waiting for input or events)
  • May call System.gc( ) to force garbage collection
/* Exercise 5.3: Write a class called Customer which has private instance variables for a name, account number and SavingsAccount. Include a constructor with a String, long, and double parameters which instantiates a SavingsAccount using the double parameter. Also include accessors (get) for each instance variable and a mutator(set) for the name only. You MUST also write the UML class diagram for this class.*/
public class Exercise_5_3_Customer
{
    private String s_CustomerName;
    private long l_CustomerAcctNum;
    private Exercise_5_3_SavingsAccount oExercise_5_3_SavingsAccount;
   
    public Exercise_5_3_Customer()
    {
        oExercise_5_3_SavingsAccount = new Exercise_5_3_SavingsAccount();        // in case, might prevent exception
    }
    public Exercise_5_3_Customer(String customerName, long customerAcctNum, double balance)
    {
        s_CustomerName = customerName;
        l_CustomerAcctNum = customerAcctNum;
        oExercise_5_3_SavingsAccount = new Exercise_5_3_SavingsAccount(balance);
    }
   
    public String getCustomerName()
    {
        return s_CustomerName;
    }
   
    public long getCustomerAcctNum()
    {
        return l_CustomerAcctNum;
    }
   
    public Exercise_5_3_SavingsAccount getSavingsAccount()
    {
        return oExercise_5_3_SavingsAccount;
    }
   
    public void setCustomerName(String CustomerName)
    {
        s_CustomerName = CustomerName;                            // is it require to check for empty string ??
    }
   
    public void display()
    {
        System.out.println("Customer Name: " + s_CustomerName);
        System.out.println("Customer A/C no: " + l_CustomerAcctNum);
        System.out.println("Customer Balance: " + oExercise_5_3_SavingsAccount.getBalance());
    }
   
    public static void main(String[] args)
    {
        // Test case
        Exercise_5_3_Customer oExercise_5_3_Customer = new Exercise_5_3_Customer("ABC", 1234567890, 1000.00);
        oExercise_5_3_Customer.display();
       
        oExercise_5_3_Customer.oExercise_5_3_SavingsAccount.transaction(500);
        oExercise_5_3_Customer.display();
    }
}
/*
-- UML diagram
----------------------
Exercise_5_3_Customer
----------------------
-s_CustomerName: String
-l_CustomerAcctNum: long
-oExercise_5_3_SavingsAccount: Exercise_5_3_SavingsAccount
----------------------
+Exercise_5_3_Customer()
+Exercise_5_3_Customer(customerName: String, customerAcctNum: long, balance: double)
+getCustomerName(): String
+getCustomerAcctNum(): long
+getSavingsAccount(): Exercise_5_3_SavingsAccount
+setCustomerName(CustomerName:String)
+display()
----------------------
*/
/*
Output:
Customer Name: ABC
Customer A/C no: 1234567890
Customer Balance: 1000.0
Customer Name: ABC
Customer A/C no: 1234567890
Customer Balance: 1500.0
*/
public class Exercise_5_3_SavingsAccount
{
    private static double annualIntRate; // default 0.
    private double balance; // default 0.
   
    public Exercise_5_3_SavingsAccount(double bal)
    {
        if( bal > 0 )
            balance = bal;
        // else leave as 0
    } // end constructor
   
    public Exercise_5_3_SavingsAccount(){ }            //default const.   
    public double getBalance(){ return balance; }
   
    public boolean transaction(double amount)
    {
        if( balance + amount >= 0 )
        {   
            balance += amount;
            return true;   
        }// end if
        return false;
    } // end transaction
   
    public double addMonthlyInterest()
    {
        double interest;
   
        interest = balance*annualIntRate/12.;
        // should be rounded to nearest 100th
        balance += interest;
        return interest;
    } // end addMonthlyInterest
   
    public static boolean modifyIntRate(double newRate)
    {
        if( newRate >= 0 )
        {
            annualIntRate= newRate;
            return true;       
        }// end if
        return false;
    } // end modifyIntRate
   
    public static double getAnnualIntRate()
    {
        return annualIntRate;
    } // end getAnnualIntRate
} // end SavingsAccount

Arrays of Objects

  • Declaring arrays of objects is the same as declaring arrays of primitive types, except the type will be a class.
  • Assigning to each element of an array of objects, however, is very different. Each element must be assigned either null (default) or an object reference.
  • When allocating memory for an array using the new operator, each element will be initialized to null unless otherwise assigned.
/* Exercise 5.4: Declare an array of Customers in main.  Write a static method (call from main) that returns an array of Customer objects. In this method, read how many Customers from the user (prompt first),  then in a for loop, prompt and read a name, account number and savings balance, which will be passed to the Customer constructor when instantiating and assigning to an array element.*/
import java.util.Scanner;
public class Exercise_5_4_CustomerArray
{
    static Scanner oScanner = new Scanner(System.in);
    private String s_CustomerName;
    private long l_CustomerAcctNum;
    private Exercise_5_3_SavingsAccount oExercise_5_3_SavingsAccount;
   
    public Exercise_5_4_CustomerArray()
    {
        oExercise_5_3_SavingsAccount = new Exercise_5_3_SavingsAccount();        // in case, might prevent exception
    }
    public Exercise_5_4_CustomerArray(String customerName, long customerAcctNum, double balance)
    {
        s_CustomerName = customerName;
        l_CustomerAcctNum = customerAcctNum;
        oExercise_5_3_SavingsAccount = new Exercise_5_3_SavingsAccount(balance);
    }
    public String getCustomerName()
    {
        return s_CustomerName;
    }
    public long getCustomerAcctNum()
    {
        return l_CustomerAcctNum;
    }
    public Exercise_5_3_SavingsAccount getSavingsAccount()
    {
        return oExercise_5_3_SavingsAccount;
    }
    public void setCustomerName(String CustomerName)
    {
        s_CustomerName = (CustomerName != null && CustomerName != "") ? CustomerName : s_CustomerName;        // Check customer name is not null or empty string from a method or main function
    }
   
    public void display()
    {
        System.out.println("Customer Name: " + s_CustomerName);
        System.out.println("Customer A/C no: " + l_CustomerAcctNum);
        System.out.println("Customer Balance: " + oExercise_5_3_SavingsAccount.getBalance());
    }
   
    // Display customer array
    public static void displayCustomerArray(Exercise_5_4_CustomerArray [] otempExercise_5_4_CustomerArray)
    {
        for(int i = 0; i < otempExercise_5_4_CustomerArray.length; i++)
        {
            System.out.println("Customer " + (i+1));
            otempExercise_5_4_CustomerArray[i].display();
        }
    }
   
    // Create array of Customers (Note: It is a static method3)
    public static Exercise_5_4_CustomerArray [] CreateCustomerArray()
    {
        int i_numOfCustomer;
        Exercise_5_4_CustomerArray [] otempExercise_5_4_CustomerArray;
        System.out.println("Enter number of customers for whom you want to create bank accounts");
        i_numOfCustomer = oScanner.nextInt();
        if(i_numOfCustomer > 0)
        {
            // Only create memory location if user entered > 0
            otempExercise_5_4_CustomerArray = new Exercise_5_4_CustomerArray[i_numOfCustomer];
            //if(otempExercise_5_4_CustomerArray[0] == null)    // it is null, memory is allocated when constructor is called later
            //    System.out.println("NULL Ha ha ha");
            String customerName;
            long accountNum;
            double balance;
           
            for(int i = 0; i < otempExercise_5_4_CustomerArray.length; i++)
            {
                // prompt and read a name, account number and savings balance
                System.out.println("Enter information for Customer " + (i+1));
                System.out.print("Name: ");
                oScanner.nextLine();                    // to flush new line before taking value from user
                customerName = oScanner.nextLine();
                System.out.print("Account #: ");
                accountNum = oScanner.nextLong();
                System.out.print("Bank Balance $: ");
                balance = oScanner.nextDouble();
                otempExercise_5_4_CustomerArray[i] = new Exercise_5_4_CustomerArray(customerName, accountNum, balance);
            }
            return otempExercise_5_4_CustomerArray;
        }
        else
        {

return null; // Handle if required

        }
    }
    public static void main(String[] args)
    {
        Exercise_5_4_CustomerArray [] oExercise_5_4_CustomerArray;
        oExercise_5_4_CustomerArray = CreateCustomerArray();
        if(oExercise_5_4_CustomerArray != null)
            displayCustomerArray(oExercise_5_4_CustomerArray);
        else
            System.out.println("No customer has been created");
    }
}

/* Output:

Enter number of customers for whom you want to create bank accounts
1
Enter information for Customer 1
Name: Firstname Lastname
Account #: 1212121
Bank Balance $: 1000
Customer 1

Customer Name: Firstname Lastname

Customer A/C no: 1212121
Customer Balance: 1000.0
*/

Static variables

  • May only be declared at class scope (not method scope)
  • Are allocated memory when the class in which it's declared is loaded
  • There is only one version of the static variable
  • May be accessed without instantiating its class
  • The order of initialization is declaration order

Static methods

  • May be called without instantiating its class
  • When called from another class, is called by giving: ClassName.methodName
  • May NOT access instance members (instance variables or methods) in its class

Static initialization block

  • Is a block of code preceded only by the keyword static
  • Is used to initialize static variables
  • A class may have more than one static initialization block
  • Get executed ONLY ONCE when the class is first loaded
  • Are executed in declaration order
  • In a static initialization block, any static variables or static methods referred to must be declared before the block
  • Is useful when the value of a static variable must be computed
Example of a static initialization block:
public class CreditAccount {
          private static double intRate;
          private static double difference = .05;
          
          static { // assume Bank class has static var.
              intRate = Bank.primeRate + difference;
              // good to use if you want a loop to initialize!
          }
          // other parts of the CreditAccount class here
} // end class CreditAccount