We are now ready to put all the pieces of a class together. Th ere is no specifi c order for methods or instance variables. However, throughout this book the following order is maintained:
1. Instance variables 2. Constructors
3. Application specifi c methods
4. Accessor methods returning the instance variable value 5. Mutator methods modifying the instance variable 6. toString method
Once again, we stress that this order is purely the author’s choice and you need not fol-low this. Th e Stock class we developed is presented in Example 3.7.
Example 3.7 /**
Keeps ticker symbol, number of shares and dividend information.
*/
class Stock {
private int numberOfShares;
private String tickerSymbol;
private double dividend;
/**
Constructs a Stock with zero shares */
public Stock() {
numberOfShares = 0;
tickerSymbol = "[NA]";
dividend = 0.0;
} /**
Computes and returns yearly dividend @return the yearly dividend
*/
Apago PDF Enhancer
public double yearlyDividend() {
double totalDividend;
totalDividend = numberOfShares * dividend;
return totalDividend;
} /**
Accessor method for the number of shares @return the number of shares
*/
public int getNumberOfShares() {
return numberOfShares;
} /**
Accessor method for the ticker symbol @return the ticker symbol
*/
public String getTickerSymbol() {
return tickerSymbol;
} /**
Accessor method for the dividend @return the dividend
*/
public double getDividend() {
return dividend;
} /**
Mutator method to set the number of shares
@param inNumberOfShares new value for the number
of shares
*/
public void setNumberOfShares(int inNumberOfShares) {
numberOfShares = inNumberOfShares;
}
Apago PDF Enhancer
/**
Mutator method to set the ticker symbol
@param inTickerSymbol new value for the ticker
symbol
*/
public void setTickerSymbol(String inTickerSymbol) {
tickerSymbol = inTickerSymbol;
}
/**
Mutator method to set the dividend
@param inDividend new value for the dividend */
public void setDividend(double inDividend) {
dividend = inDividend;
}
/**
The toString method
@return number of shares and ticker symbol */
public String toString() {
String str;
str = numberOfShares + " " + tickerSymbol;
return str;
} }
Advanced Topic 3.1: Representing Class in UML 2
As mentioned in Chapter 1, the unifi ed modeling language (UML) is a standard language for soft ware specifi cation. Th e UML uses mostly graphical notations to express the design of soft ware projects. Th e unifi ed modeling language version 2 (UML 2) is the latest version of UML. Th e UML 2 notation of the Stock class is shown in Figure 3.2.
Th ere are three distinct areas: class name area, instance variable area, and operations area. Th e − sign and + sign indicate the access modifi ers private and public, respec-tively. A simplifi ed notation for the Stock class in UML 2 notation is shown in Figure 3.3 and it is quite useful in showing relationships among classes.
Apago PDF Enhancer
TESTING
Every class you create must be tested thoroughly before it is used in any application. Th e most general approach to test a class is to create an application program and test every method of the class you have developed. Th is approach is followed in this book and is illustrated in the next example. Java development environments such as BlueJ provide the facility to test a class without an application program. Th e readers are encouraged to test their class by creating an application program.
Example 3.8
In this example we create an application to test the Stock class.
As you know by now, every application has at least one class and one of the classes of the application has a method main. Th erefore, we create an application having exactly one class that contains the method main as shown below:
public class StockTesting {
public static void main (String[] args) {
//Java statements to test Stock class }
}
Stock
+yearlyDividend() : double +getNumberOfShares() : int +getTickerSymbol() : String +getDividend() : double +setNumberOfShares(int) : void +setTickerSymbol(String) : void +setDividend(double) : void +toString():void
-numberOfShares : int -tickerSymbol : String -dividend : double
FIGURE 3.2 Class diagram of Stock class.
Stock
FIGURE 3.3 Simplifi ed class diagram of Stock class.
Apago PDF Enhancer
To begin with, to test any method of the Stock class, you must create an instance of the Stock class. Th e required Java statement is
Stock testStock = new Stock(); //(1)
Th e left -hand side of the above assignment statement declares a reference variable testStock of the type Stock. Th e right-hand side creates a new object belonging to the Stock class and returns the reference. In fact the new on the right-hand side is an operator that creates an instance of the class on the basis of the constructor that follows. For example, Stock() is a constructor with no formal parameter.
Such a constructor is known as default constructor and is present in every class by default so long as there is no user-defi ned constructor. A default constructor initial-izes every instance variable of the object with default values. In this example, we have already included a constructor with no formal parameter, and therefore the right-hand side of Statement 1 creates an instance of the Stock class, initializes numberOfShares to 0, tickerSymbol to "[NA]", and dividend to 0.0.
Th e new operator returns the reference of the object created. Th us, the variable testStock has the reference of the new object created. Note that Statement 1 is equivalent to the following two statements:
Stock testStock; //(2) testStock = new Stock(); //(3)
Statement 2 declares a local variable testStock. Statement 3 creates a new instance of Stock and initializes the reference variable testStock with the ref-erence of the newly created instance returned by the new operator. In other words, Statement 3 instantiates the local variable testStock.
Now to test a pair of accessor and mutator methods corresponding to an instance variable, the best way is to get an input value, use the mutator method to store it, and then output it with the help of corresponding accessor method. Once all instance variables received valid data values, application specifi c methods and toString method can be tested. Th us, we have the following Java application program:
import java.util.Scanner;
/**
An application class to test Stock class
*/
public class StockTesting {
public static void main (String[] args)
Apago PDF Enhancer
{
//Create an object belonging to the class Stock Stock testStock = new Stock();
//Declare local variables
int inputNumberOfShares, outputNumberOfShares;
String inputTickerSymbol, outputTickerSymbol;
double inputDividend, outputDividend;
double outputYearlyDividend;
//Get input values
Scanner scannedInfo = new Scanner(System.in);
System.out.print("Enter numbers own, stock symbol"
+ " and dividend : ");
System.out.flush();
inputNumberOfShares = scannedInfo.nextInt();
inputTickerSymbol = scannedInfo.next();
inputDividend = scannedInfo.nextDouble();
System.out.println();
//Test mutator and accessor methods
testStock.setNumberOfShares(inputNumberOfShares);
testStock.setTickerSymbol(inputTickerSymbol);
testStock.setDividend(inputDividend);
outputNumberOfShares
= testStock.getNumberOfShares ();
outputTickerSymbol = testStock.getTickerSymbol();
outputDividend = testStock.getDividend();
System.out.println("Number of shares : " +
outputNumberOfShares);
System.out.println("Stock symbol is : " +
outputTickerSymbol);
System.out.println("Dividend per share is : " + outputDividend);
//Test yearlyDividend method
outputYearlyDividend = testStock.yearlyDividend();
System.out.println("Yearly Dividend is : " +
outputYearlyDividend);
//Test toString method
Apago PDF Enhancer
System.out.println(testStock.toString());
} }
Output
Enter numbers own, stock symbol and dividend: 500 XYZ 1.43 Number of shares : 500
Stock symbol : XYZ
Dividend per share : 1.43 Yearly Dividend : 715.0 500 XYZ
Self-Check 29. True or false: Every class needs to be tested.
30. Testing will help identify errors.
Advanced Topic 3.2: Representing Relationship in UML 2
Th e UML 2 class diagram of StockTesting application is presented in Figure 3.4. Th e association is the most common relationship that exists among classes and it represents the relationship among instances of classes. Th e multiplicity of the association denotes
Stock
+yearlyDividend() : double +getNumberOfShares() : int +getTickerSymbol() : String +getDividend() : double +setNumberOfShares(int) : void +setTickerSymbol(String) : void +setDividend(double) : void +toString():void
-numberOfShares : int -tickerSymbol : String -dividend : double StockTesting
+main(String[]) : void 1 uses
1..*
FIGURE 3.4 Class diagram of StockTesting application.
Apago PDF Enhancer
the number of objects participating in such a relationship. For example, an instance of the class StockTesting uses one or more instances of the class Stock. Th us, there is an association between class StockTesting and class Stock. Th e number 1 appearing near the class StockTesting indicates that corresponding to one Stock object there is 1 StockTesting object and the notation 1..* appearing near the class Stock indicates that corresponding to one StockTesting object there can be 1 to many Stock objects.
Both 1 and 1..* are known as the multiplicity.
Advanced Topic 3.3: Class Design, Implementation, and Testing
In this section, we continue with the soft ware development process outlined in Chapter 1.
As mentioned in Chapter 1, design, implementation, and testing phases are covered in this section. We list them fi rst for easy reference and then proceed to elaborate on each of those phases through an example.
Phase 2. Design
Step 1. Decide on attributes Step 2. Decide on methods
Phase 3. Implementation (or create classes using Java constructs) Phase 4. Testing
Design
Th e primary aim of this phase is to decide on various classes required and assign respon-sibilities to each one of them. Design of the soft ware begins with a formal specifi cation of the intended product. Th e following is an example of a formal specifi cation of a circular counter.
Example 3.9
A circular counter counts 0, 1, 2, …, limit − 1. Once the counter reaches limit − 1, the next value is not limit, rather it is 0. In other words, a circular counter can count up to limit − 1 and then it resets to 0. Th e value of the limit can be any integer greater than 1.
From the above specifi cation, it is quite clear that the soft ware we develop must provide a “get counter value” service to the user. Without such a service, the counter is of no use. Being a counter, there needs to be service to “increment the counter value.” Another useful service is “set counter value.” Being a circular counter, there is a limit value and there needs to be services to set and get the limit value. On the basis of this analysis, we can create the use case diagram given in Figure 3.5.
Th e design phase starts where the use case analysis left off . Th us in this example, from the use case diagram given in Figure 3.5, we tentatively decide to have one class named CircularCounter.
Apago PDF Enhancer
Decide on Attributes
From the use case diagram, it is quite clear that the circular counter must keep the current value of the counter and limit value. Clearly, both of these values can be of int data type.
Th erefore, the CircularCounter class needs the following two attributes:
private int counterValue;
private int limitValue;
Decide on Methods
In this step you need to decide on methods. As explained before, you may include accessor and mutator methods corresponding to each instance variable. You may also provide a toString method. So in this section the focus is on additional methods that are needed for this class to meet its specifi cations.
Th e “increment counter” is the only use case that needs to be addressed. Th erefore, there must be a method to increment the counter value by one. In this case, you must clearly state preconditions and postconditions. Preconditions refer to the necessary condi-tions for the method to behave as specifi ed. Postcondicondi-tions refer to the condicondi-tions satisfi ed by inst ance variables at the completion of the method invocation. Th e set of values of all instance variables is called the state of an object. Th us, preconditions and postconditions specify the states of an object before and aft er a method have been invoked. In this case, the
Circular counter
Set counter
User
Get counter
Increment counter
Set limit value
Get limit value
FIGURE 3.5 Use case diagram for the circular counter.
Apago PDF Enhancer
preconditions are limitValue > 0 and 0 ≤ counterValue < limitValue. Th e post-conditions are limitValue > 0, 0 ≤ counterValue < limitValue and counter-Value is incremented by 1 in the circular order 0, 1, 2, ..., limitValue - 1, 0.
Th us, the class has the following six methods:
public void incrementCounterValue() // Preconditions : limitValue > 0;
// 0 ≤ counterValue < limitValue.
// Postconditions : limitValue > 0;
// 0 ≤ counterValue < limitValue;
// counterValue is incremented by 1
// in the circular order
// 0, 1, 2, ..., limitValue - 1, 0.
public int getCounterValue() public int getLimitValue()
public void setCounterValue(int inCounterValue) public void setLimitValue(int inLimitValue) public void toString()
Consider the following expression:
(counterValue + 1) % limitValue
Assume that limitValueis 5. Now counterValuehas to be one of the following: 0, 1, 2, 3, and 4. Let us evaluate the above expression for each of those values (see Table 3.2).
Th us, the above expression computes the next value based on counterValue as desired. Th erefore, the Java statement
counterValue = (counterValue + 1) % limitValue
increments instance variable counterValue in circular order 0, 1, 2, ..., limitValue - 1,0.
Th e circular counter can be visualized as in Figure 3.6 and the class diagram is given in Figure 3.7.
TABLE 3.2 Illustration of Circular Increment
counterValue (counterValue +1) % limitValue
0 (0 + 1) % 5 = 1 % 5 = 1
1 (1 + 1) % 5 = 2 % 5 = 2
2 (2 + 1) % 5 = 3 % 5 = 3
3 (3 + 1) % 5 = 4 % 5 = 4
4 (4 + 1) % 5 = 5 % 5 = 0
Apago PDF Enhancer
Implementation
In this phase, we use Java programming language to code the class(es) designed in the design phase.
/**
Circular counter counts 0, ..., limit - 1, 0
*/
public class CircularCounter {
private int counterValue;
private int limitValue;
/**
Constructs a circular counter limitValue 100;
counterValue 0.
*/
public CircularCounter() {
counterValue = 0;
CircularCounter
− counterValue : int
− limitValue : int
+incrementCounterValue() : void +getCounterValue() : int +getLimitValue() : int +setCounterValue(int) : void +setLimitValue(int) : void +toString() : String
FIGURE 3.7 Class diagram of CircularCounter class.
CircularCounter
counterValue
limitValue
FIGURE 3.6 Visualization of CircularCounter.
Apago PDF Enhancer
limitValue = 100;
} /**
Increments the circular counter */
public void incrementCounterValue() {
counterValue = (counterValue + 1) % limitValue;
} /**
Accessor method for the counter value @return the counter value
*/
public int getCounterValue() {
return counterValue;
} /**
Accessor method for the limit value @return the limit value
*/
public int getLimitValue() {
return limitValue;
} /**
Mutator method to set the counter value
@param inCounterValue new value for the counter value */
public void setCounterValue(int inCounterValue) {
counterValue = inCounterValue % limitValue;
} /**
Mutator method to set the limit value
@param inLimitValue new value for the limit value */
public void setLimitValue(int inLimitValue)
Apago PDF Enhancer
{
limitValue = inLimitValue;
} /**
The toString method
@return counter value and limit information */
public String toString() {
String str;
str = "Counter (0 to " + (limitValue - 1) + ") value : "
+ counterValue;
return str;
} } Testing
In this phase we create an application program to test the class CircularCounter. Th e UML 2 diagram is shown in Figure 3.8 and the code is as follows:
import java.util.Scanner;
/**
The application tester class for circular counter
*/
public class CircularCounterTesting {
public static void main (String[] args) {
//Create an instance of CircularCounter CircularCounter testCir cularCounter = new
CircularCounter();
//Declare variables to input and output counterValue // and limitValue
int inputCounterValue, outputCounterValue;
int inputLimitValue, outputLimitValue;
int outputIncrementCounterValue;
//Get two input values
Scanner scannedInfo = new Scanner(System.in);
Apago PDF Enhancer
System.out.print("Enter counter value and limit value : ");
System.out.flush();
inputCounterValue = scannedInfo.nextInt();
inputLimitValue = scannedInfo.nextInt();
System.out.println();
//Test mutator and accessor corresponding //to instance variables.
testCircularCounter.setCounterValue(inputCounterValue);
testCircularCounter.setLimitValue(inputLimitValue);
outputCounterValue =
testCircularCounter.getCounterValue();
outputLimitValue =
testCircularCounter.getLimitValue();
System.out.println("Counter value : "+
outputCounterValue);
System.out.println("Limit value : "+
outputLimitValue);
//Test incrementCounterValue method
System.out.println("Counter is incremented
five times ");
System.out.println(testCircularCounter);
testCircularCounter.incrementCounterValue();
System.out.println(testCircularCounter);
testCircularCounter.incrementCounterValue();
System.out.println(testCircularCounter);
testCircularCounter.incrementCounterValue();
System.out.println(testCircularCounter);
testCircularCounter.incrementCounterValue();
System.out.println(testCircularCounter);
testCircularCounter.incrementCounterValue();
System.out.println(testCircularCounter);
} }
Output
Enter counter value and limit value : 3 5 Counter value : 3
Limit value : 5
Apago PDF Enhancer
FIGURE 3.8 Class diagram of circular testing program.
+main(String[]) : void
1 uses
1..*
CircularCounter
+incrementCounterValue() : void +getCounterValue() : int +getLimitValue() : int +setCounterValue(int) : void +setLimitValue(int) : void +toString() : String
− counterValue : int
− limitValue : int CircularCounterTesting
Counter is incremented five times Counter (0 to 4) value : 3
Counter (0 to 4) value : 4 Counter (0 to 4) value : 0 Counter (0 to 4) value : 1 Counter (0 to 4) value : 2 Counter (0 to 4) value : 3
Note 3.1 Compare Figures 3.4 and 3.8. Observe that the essential diff erence is that in Fig-ure 3.4 we have the Stock class and in FigFig-ure 3.8 we have CircularCounter class. In other words, once the UML 2 class diagram for a class is created, the UML 2 class diagram for the corresponding testing program is quite obvious. Th erefore, we omit such fi gures.
REVIEW
1. A class has attributes and operations: attributes are used to store the data, and opera-tions access and manipulate the data values.
2. Keeping data along with operations is known as encapsulation.
3. Unless there is a very compelling reason, all attributes are declared as private.
4. A private attribute (or operation) is accessible only to the object.
Apago PDF Enhancer
5. A public attribute (or operation) is accessible to any object.
6. Operations of a class are generally declared as public.
7. Implementation of an operation is called a method.
8. Operations provide the necessary interface to initialize or modify an attribute, retrieve the current value of an attribute, and compute a new value based on current value of attributes.
9. A Java program is a collection of collaborating objects.
10. Th e syntax for invoking a method using a reference variable is referenceVariableName.methodName();
Th e reference variable is called an explicit parameter.
11. Th ere are two types of methods: value returning methods and void methods.
12. A void method cannot be invoked in an expression. It is invoked as a stand-alone Java statement.
13. A value returning method can be invoked in an assignment statement or can be used in an expression or as part of an output statement. If the value returned is not stored using an assignment statement, it will be lost forever.
14. A method has two parts: the header
public static void main (String[] args) and the body
{
[statements]
}
15. Th e header ends with a list of formal parameters (or arguments) enclosed within a pair of parentheses. Th e list of formal parameters in a method header can be empty. How-ever, the pair of parentheses enclosing the formal parameter cannot be omitted.
16. As part of the method invocation, the actual parameter value is copied into the for-mal parameter.
17. Inside a method, you can declare additional variables. All variables declared inside a method, excluding the formal parameters in the header, are known as local variables.
18. A local variable is not accessible outside the block. Th erefore, no access modifi er is required.
Apago PDF Enhancer
19. An instance variable is available only within the object (if it is declared private).
A local variable is available only within the block from its point of declaration.
A formal parameter is available within the method.
20. An instance variable exists as long as the associated object exists. A local variable is created every time declaration statement is executed during the method execution and the variable ceases to exist upon the completion of the block. A formal parameter is created at the beginning of the method invocation and it ceases to exist upon the completion of the method.
21. At the beginning of the method invocation, the actual parameter value is copied to the formal parameter.
22. Once the return statement is executed, the control goes back to the Java statement that invoked the method.
23. A method that does not modify any instance variable of an object is called an acces-sor method. All other methods are known as mutator methods.
EXERCISES
1. Mark the following statements as true or false:
a. An accessor method can access only one attribute.
b. Th ere are two types of methods: value returning and void.
c. A mutator method modifi es at least one attribute.
d. A local variable can be made accessible outside the method by declaring it as public.
e. It is okay for a void method to return 0.
f. Every value returning method must have a return statement.
g. Every class must have a toString method.
h. Th e default constructor has no formal parameters.
i. A void method cannot be used on the right-hand side of an assignment statement.
j. Th e method main need not be a static method.
k. Th e method charAt of the String class is of type char.
l. Every method must have a return statement.
2. Mark the following method invocation as valid or invalid. If invalid, explain why it is invalid. Assume that scannedInfo is a reference variable of type Scanner, word is a reference variable of the type String, that references the String “Okay, Ready to go!” and stk is a reference variable of the type Stock.
2. Mark the following method invocation as valid or invalid. If invalid, explain why it is invalid. Assume that scannedInfo is a reference variable of type Scanner, word is a reference variable of the type String, that references the String “Okay, Ready to go!” and stk is a reference variable of the type Stock.