COMP101 - COMPOUND DATA TYPES AND ARRAYS INTRODUCTION TO PROGRAMMING IN JAVA: COMPOUND DATA TYPES AND ARRAYS NOTE: This set of www pages is not the set of www pages for the curent version of COMP101. The pages are from a previous version that, at the request of students, I have kept on line. CONTENTS 1. Introduction to compound data types 2. Arrays 2.1. Features of arrays 3. Array declaration 4. Assignment 5. Example problem - metres to yards, feet and inches conversion 5.1. Requirements 5.2. Analysis 5.3. Design 5.4. Implementation 5.5. Testing Note: The programming example given here makes use of a default constructor. 1. INTRODUCTION TO COMPOUND DATA TYPES The available primitive (basic) types can be extended by adding compound types made up of existing primitive types (and/or other compound types). Compound types are usually programmer defined. There are some standard compound types which available in many (object oriented and imperative) programming languages. These include: Arrays Strings We will be discussing both of these. 2. ARRAYS The most straight forward (and oldest) form of compound data type is the array. All the types we have considered so far have been scaler (data items of the types considered can only have one value). In an array a data item consists of a numbered collection of similar items. As such it can be viewed as simply a collection of data items, all of the same type, stored in a series of locations in memory such that a single value is held at each location This is illustarted in Figure 1 where we have an array intended to store a collection of 10 data items. Figure 1: 2.1. Features of arrays Items in arrays are called elements (some authors use the term cell to describe the locations within an array). The number of elements in an array is described by its length. The array in Figure 1 has a length of 10. Specific elements in an array can be identified through the use of an index. In Java the index is always of the type integer (this is not the case in all programming languages). In Java the first index is always the integer 0 which is referred to as the lower bound, the last index is then referred to as the upper bound. The upper bound for the array given in Figure 1 is 9. Note that: upperBound = length-1 3. ARRAY DECLARATIONS When declaring arrays we are doing two things: Declaring the type of the array, i.e. the type of the elements to be contained within it. Declaring the array length (and by extension the upper bound, which is the array length minus one --- indexing starts at 0). In Java, to declare an array data item we use a declaration statement of the form:
< TYPE_NAME > [] arrayName;
Without the [] this tell the Java compiler to create space for an integer data item called arrayName. The [] then indicates that this is actually the start of an unspecified array of integers. The value associated with the array name is an address, i.e. a reference value (Figure 2), that marks the start of a block of memory. So that an appropriate amount of memory can be set aside we must also tell the compiler how many elements to expect. We do this as follows:
< TYPE_NAME > [] arrayName = new
< TYPE_NAME > [N]
where N is the number of elements. Note the similarity between the above and the way we declared an object:
< CLASS_NAME > objectName = new
< CONSTRUCTOR >
( < ARGUMENT_LIST > )
In many ways we can also consider a class to be a compound type. Let us consider an example of an array declaration:
int [] temperatureArray =
new int[10];
Here we have created an array of 10 integers called temperatureArray (presumably to store a sequence of temperatures in). Alternatively, if we wish to store our temperatures as doubles we would have declared the array as follows:
double [] temperatureArray =
new double[10];
Note that if we has not used an array to store our temperatures we would have had to declare 10 distinct data items:
double temperature0;
double temperature1;
double temperature2;
double temperature3;
double temperature4;
double temperature5;
double temperature6;
double temperature7;
double temperature8;
double temperature9;
Very tedious for small numbers of elements and completely impractical for any number of elements beyond (say) 50. Figure 2: Object reference data item 4. ASSIGNMENT AND INITIALISATION Assignment: Given knowledge of the index for an array element we can assign a value to that element (or change its value) using an "assignment" operation. Example:
myArray[0] = 4;
Here we have an array data item (named myArray) and we have assigned a value of 4 to the first element of this array (i.e. the element at index 0). Note how we have specified the element we are interested in by indexing into the array. Initialisation: Remember that initialisation is the process of assigning an "initial" value to a data item on declaration. Java (along with many other programming languages) supports the concept of compound values (also sometimes referred to as array aggregates) which allow all the elements of an array to be assigned to simultaneously on initialisation:
int[] myArray =
{9,8,7,6,5,4,3,2,1,0};
Note that we do not need to define the length in this case as this can be deduced by the Java compiler. 5. EXAMPLE PROBLEM - METRES TO YARDS FEET AND INCHES CONVERSION 5.1 Requirements Design and create a Java application that, when presented with a distance given in Metres converts it to a distance measure comprising Yards, Feet and Inches (1 Metre = 39.37 Inches). Output the result in whole Yards, Feet and Inches. Assume that the distance to be processed is a positive integer between 1 and 1x10^6 Metres. 5.2 Analysis We can divide the problem into a conversion class and an application class (Figure 2). We will represent the required imperial distance using a three element integer array. Note that, for the DistanceConversion class we will be using a default constructor. Figure 3: Class diagram for distance conversion problem 5.3 Design From Figure 2 we can identify the following class contents. 5.3.1 DistanceConversion Class Field Summary private final static double CONVERSION_FACTOR A class constant, set to 39.37 to convert Metres to Inches. private final static int INCHES_IN_ONE_YARD A class constant, set to 36 to convert Yards to Inches. private final static int INCHES_IN_ONE_FOOT A class constant, set to 12 to convert Feet to Inches. private int[] yardsFeetAndInches An instance field for a three element integer array in which to store a distance comprising yards, feet and inches. Method Summary public void metDist2impDist(int metDistance) Method to carry out the required conversion. public void outputYardsFeetAndInches() Method to output contents of yardsFeetAndInches array. Has no data items of its own. Note: As we do not wish to pass any arguments when we create an instance of the class DistanceConversion we can make use of the default constructor for the class, i.e. we do not need to define explicitly a constructor for the class. 5.3.2 DistConvertApp Class Field Summary private static Scanner keyboardInput A class instance to facilitate input from the input stream. Method Summary public static void main(String[] args) Main method to allow a user to input a metric distance and then cause that to be converted and output as an imperial distance. The newDistConvert instance is created using the DistanceConversion default constructor. We should now present a Nassi-Shneiderman designs for the above, but as these are straight forward involving no loops or choice points and in the interest of brevity, we shall not do so on this occasion. 5.4. Implementation The implementation for the above is presented in Tables 1 and 2. The metDist2impDist method operates as follows: A metric distance is passed to the method as an argument of type int, for discussion purposes let us assume that the value 4 is passed in. We convert the given metric distance to inches by multiplying by the constant CONVERSION_FACTOR (39.37). The constant is a double while the metric distance is an integer, we are therefore doing mixed mode arithmetic. When multiplying a real number by an integer the integer gets automatically coerced to a real number (nothing is lost by promoting an integer to a real), however in the example we use a cast so that the conversion is done explicitly. The result of 4.0*39.37 is 157.48 (a real number); however we wish to assign this result to an integer data item (inches). A real number can not be automatically coerced to become an integer (as the decimal part of the real number would be lost), we must therefore do this explicitly using a cast. What we are saying to the compiler is "yes, we know the decimal part of the real number will be lost, but this is what we want to happen". As a consequence the value 157.48 becomes 157 and is assigned to the data item inches. We then calculate the number of yards that make up our metric distance by dividing our inches data item by the constant INCHES_IN_ONE_YARD (36). In this case both the dividend and the divisor are of type int (integer division) therefore the quotient will also be of type int, i.e. 157/36=4. (If either or both the dividend and the divisor are real numbers the quotient will be a real number.) This result (4 in our example) is then assigned to the first element in the yardsFeetAndInches array (index = 0). We then need to calculate the remaining inches that do not make up a whole yard:
inches = inches - (yardsFeetAndInches[0] * INCHES_IN_ONE_YARD)
= 157 - (4 * 36)
= 157 - 144
= 13
Next we calculate the number of feet represented by the remaining inches by dividing the inches data item (with its current value of 13 in our example) by the constant INCHES_IN_ONE_FOOT (12). Again what we are doing here is integer division so the result will also be an integer: 13/12=1. This result will then be assigned to the second element of the yardsFeetAndInches array (index = 1). The remaining inches (that do not make up whole yards and/or feet) are then calculated:
inches = inches - (yardsFeetAndInches[1] * INCHES_IN_ONE_FOOT)
= 13 - (1 * 12) = 13 - 12 = 1
This last value (1 in this case) is then assigned to the third element of the yardsFeetAndInches array (index = 2), and the conversion is complete.
// DISTANCE CONVERSION
// Frans Coenen
// 28 June 1999
// Dept Computer Science, University of Liverpool
class DistanceConversion {
// ------------------ FIELDS ------------------------
private final static double CONVERSION_FACTOR = 39.37;
private final static int INCHES_IN_ONE_YARD = 36;
private final static int INCHES_IN_ONE_FOOT = 12;
private int[] yardsFeetAndInches = new int[3];
// ------------------ METHODS ------------------------
/* CONVERT METRIC DISTANCE TO IMPERIAL DISTANCE */
public void metDist2impDist(int metDistance) {
// Metres to inches
int inches = (int) ((double) metDistance * CONVERSION_FACTOR);
// Yards
yardsFeetAndInches[0] = inches/INCHES_IN_ONE_YARD;
inches = inches - (yardsFeetAndInches[0] * INCHES_IN_ONE_YARD);
// Feet
yardsFeetAndInches[1] = inches/INCHES_IN_ONE_FOOT;
inches = inches - (yardsFeetAndInches[1] * INCHES_IN_ONE_FOOT);
// Inches
yardsFeetAndInches[2] = inches;
}
/* OUTPUT CONTENTS OF YARDS FEET AND INCHES ARRAY */
public void outputYardsFeetAndInches() {
System.out.println(yardsFeetAndInches[0] + " (Y), " +
yardsFeetAndInches[1] + " (F), " + yardsFeetAndInches[2] + " (I).");
}
}
Table 1: Distance conversion class implementation
// DISTANCE CONVERSION APPLICATION
// Frans Coenen
// 28 June 1999
// Revised Friday 26 August 2005
// Dept Computer Science, University of Liverpool
import java.util.*;
class DistConvertApp {
// ------------------- FIELDS ------------------------
// Create Scanner class instance
public static Scanner keyboardInput = new Scanner(System.in);
// ------------------ METHODS ------------------------
/* Main method */
public static void main(String[] args) {
int metricDistance;
// Input a distance
System.out.print("Input a metric distance ");
metricDistance = keyboardInput.nextInt();
// Do the conversion
DistanceConversion newDistConvert = new DistanceConversion();
newDistConvert.metDist2impDist(metricDistance);
// End
newDistConvert.outputYardsFeetAndInches();
}
}
Table 2: Distance conversion application implementation The technique used here to represent a measure made up of several elements is often encountered. For example we could use the approach in the date validation program to describe dates; the day, month and year could be represented in terms of a three element integer array. 5.5. Testing 5.5.1 Black Box Testing Arithmetic testing: We should include test cases to ensure correct operation of arithmetic expressions. In this case it is appropriate to test each such expression with positive and zero sample values where applicable. In addition it would be a good idea here to include a test where a positive number of feet results and where zero feet result. By the same token we should contrive to test the situation where the number of inches is 0. (Note that the specification of the problem is such that we cannot contrive a test case where the number of metres is 0). An appropriate set of test cases is given in the table below. TEST CASE EXPECTED RESULT METRES OUTPUT 0 [0, 0, 0] 1 [1, 0, 3] 4 [4, 1, 1] 100 [109, 1, 0] The results from running the above test cases are presented in Table 3.
$ java DistConvertApp
Input a metric distance 0
0 (Y), 0 (F), 0 (I).
$ java DistConvertApp
Input a metric distance 1
1 (Y), 0 (F), 3 (I).
$ java DistConvertApp
Input a metric distance 4
4 (Y), 1 (F), 1 (I).
$ java DistConvertApp
Input a metric distance 100
109 (Y), 1 (F), 0 (I).
Table 3: Sample output Created and maintained by Frans Coenen. Last updated 10 February 2015