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