The goal of this lab is to practice developing type-safe collection classes and iterators.
Portions of this lab were developed by Prof. Michael Kirkpatrick.
In this activity we will be working with a Pair
class that represents a 2-tuple. (Recall that a tuple
is a finite ordered sequence of elements. A 2-tuple contains two
elements, a 3-tuple contains three elements, an n-tuple contains
n elements.)
A Pair class could be useful any time we need to store
data that naturally occurs as an ordered pair: first and last name,
two-dimensional coordinates, etc.
Download the following files. The first is our
initial Pair implementation and the second is a driver
class that illustrates its use. Take a few minutes to read both
files. (Ignore the test file for now.)
Both of these files should compile with no errors or warnings, but
there is a logic error in the
main method that will cause the driver to crash when
largestStadium is passed
the stadiums array. Find the problem
but DON'T fix it. (Don't panic if you aren't sure
what the error is. It should become clear later on in the lab.)
Our existing Pair class is flexible: it can be used to
store objects of any type. Unfortunately, it is both dangerous and
inconvenient. It is dangerous because we may accidentally store an
object of an unexpected type (as you saw above). It is inconvenient
because we will usually need to cast objects retrieved from
a Pair before they can be used.
We can address these issues by making our Pair class
generic. Our improved class will accept two type parameters since
we may want the type of the first element to be different from the
type of the second. Complete the following steps.
PairTest.java. All tests should pass.testPairIntegerInteger method so that the
Pair is parameterized for two Integers. In other words, instead of this:
Pair pair = new Pair(1, 2);
pair should be declared and instantiated like this:
Pair<Integer, Integer> pair = new Pair<Integer, Integer>(1, 2);
or like this:
Pair<Integer, Integer> pair = new Pair<>(1, 2);
Next, eliminate the unnecessary casts to Integer in the calls to
assertEquals. Note that your tests will not
compile at this point. You still need to modify
the Pair class to accept type arguments. This
is an example of "test driven development": we are writing
the tests before we develop the required
functionality.assertEquals requires a
third parameter for comparing doubles.Pair class to use generics so that
it passes these three test cases. Note that all uses
of Object should be replaced with a generic
parameter. Object should not appear anywhere in
the finished class.PairTest.Pair to pass these test cases.
Take another look at the PairDriver.java file. Your IDE
should now be showing multiple warnings indicating that you
aren't using the Pair class correctly: no type arguments are being
provided.
Complete the following steps.
Add type arguments so that the Pair instances
all have String for the first object
and Integer for the second.
Note that attempting to instantiate an array as follows will not compile:
Pair<String, Integer>[] stadiums = new Pair<String, Integer>[3];(If you are interested in why, check out this blog post.) Instead we need to instantiate the array without type arguments:
Pair<String, Integer>[] stadiums = new Pair[3];This will result in a warning along the lines of "Type safety: The expression of type Pair[] needs unchecked conversion to conform to Pair<String,Integer>[]", which can be suppressed using the
@SuppressWarnings("unchecked") annotation. NOTE:
99% of the time ignoring or suppressing warnings is a BAD IDEA. This
is a rare exception.
Re-compile and observe the difference. At this point, the
compiler should catch the logic error in
the PairDriver main method. This
is a key advantage of generics. They allow us to create
classes that can work with any type, while still enforcing
type expectations. This is why generic classes are
sometimes referred to as "type-safe". Go ahead and fix the
logic error now and test the resulting code.
largestStadium? Why or
why not? If you can, then go ahead and do so.
Now that you have a completed generic Pair class, you
will create a minimally functioning collection of Pair
objects. Open up the following files in your favorite IDE.
Take a few minutes to read the code, then complete the unfinished methods according to the provided comments.
Submit the following files through Canvas:
Pair.java
PairTest.java
PairDriver.java
PairList.java