Instructions:
Answer the following questions one at a time. After answering each question,
check your answer (by clicking on the check-mark icon if it is available)
before proceeding to the next question.
Getting Ready:
Before going any further, you should:
Depending on your development environment, create either a
directory or a project for this lab.
to an appropriate directory/folder. (In most browsers/OSs, the
easiest way to do this is by right-clicking/control-clicking on
each of the links above.)
1. Overloading Methods:
This part of the lab will give you some experience writing overloaded
methods.
The current version of the Test class has multiple methods
that test for equality, each with a slightly different name and different
parameters. Modify the code so that it now has three overloaded
forEqual() methods one with double parameters
one with int parameters, and one with String
parameters. What does the class look like now?
solution/Test.java
/**
* A simple unit testing harness.
*
* @author Prof. David Bernstein, James Madison University
* @version 3.0 (Uses overlaoded methods)
*/
public class Test {
/**
* Display an alert if the actual double value and the expected double
* value differ by more than the given tolerance.
*
* @param description A description of the test
* @param expected The expected value
* @param actual The actual value
* @param tolerance The tolerance
*/
public static void forEqual(String description,
double expected, double actual,
double tolerance) {
double difference;
difference = Math.abs(expected - actual);
if (difference > tolerance) {
System.out.printf("%s Expected: %5.2f, Actual: %5.2f\n",
description, expected, actual);
}
}
/**
* Display an alert if the actual int value is not equal to the
* expected value.
*
* @param description A description of the test
* @param expected The expected value
* @param actual The actual value
*/
public static void forEqual(String description,
int expected, int actual) {
if (expected != actual) {
System.out.printf("%s Expected: %d, Actual: %d\n",
description, expected, actual);
}
}
/**
* Display an alert if the contents of the actual String object
* is not not equal to the contents of the expected value String object.
*
* @param description A description of the test
* @param expected The expected value
* @param actual The actual value
*/
public static void forEqual(String description,
String expected, String actual) {
if (!expected.equals(actual)) {
System.out.printf("%s Expected: %s, Actual: %s\n",
description, expected, actual);
}
}
/**
* Display an alert if the actual boolean is not false.
*
* @param description A description of the test
* @param actual The actual value
*/
public static void forFalse(String description,
boolean actual) {
if (actual) {
System.out.printf("%s Expected: false, Actual: true\n",
description);
}
}
/**
* Display an alert if the actual boolean is not true.
*
* @param description A description of the test
* @param actual The actual value
*/
public static void forTrue(String description,
boolean actual) {
if (!actual) {
System.out.printf("%s Expected: true, Actual: false\n",
description);
}
}
}
Copy the JMUPhoneNumberDriver class
you wrote for the lab on information hiding to your working
directory.
Modify this class so that it uses the new version of the Test
class. (Hint: Use Find/Replace.)
Copy the JMUPhoneNumber class you wrote for the
lab on information hiding to your working directory.
Overload the setExchange() method with a new version that
is passed a single char. If the actual parameter is
a '6' this method should set the exchange to DORM,
otherwise it should set the exchange to OFFICE.
/**
* Set the exchange
*
* @param x Either '6' or '8'
*/
public void setExchange(char x)
{
if (x == '6') setExchange(DORM);
else setExchange(OFFICE);
}
Why can't this version of the setExchange() method
have an int parameter?
Because there is already a method with that name that has an int
parameter.
Modify your driver so that it can be used to test the
setExchange() methods.
Execute your driver and test these methods.
Overload the toString() method with a new version that
is passed an int format code. (This method must
not change the format associated with the JMUPhoneNumber
object even temporarily.
It must use the parameter that it is passed to create the
String it returns.)
This method is an exact copy of the original version. However, now because
format is a parameter, the parameter will be used rather than the
attribute.
Why should one version of the toString() method call the
other version?
To avoid code duplication.
Modify the toString() methods so that one calls the other.
solution/JMUPhoneNumber.java
(Fragment: toString)
/**
* Returns a formatted String representation of this JMUPhoneNumber
* (see the discussion of the setFormat method)
*/
public String toString()
{
return toString(this.format);
}
/**
* Returns a formatted String representation of this JMUPhoneNumber
* (see the discussion of the setFormat method)
*
* @param tempFormat The format code to use
*/
public String toString(int tempFormat)
{
String fourDigitExtension, result;
fourDigitExtension = String.format("%04d",extension);
result = "";
if (tempFormat == US_OLD)
{
result = "("+areaCode+") "+exchange+"-"+fourDigitExtension;
}
else if (tempFormat == US_NEW)
{
result = areaCode+"-"+exchange+"-"+fourDigitExtension;
}
else if (tempFormat == EUROPE)
{
result = areaCode+"."+exchange+"."+fourDigitExtension;
}
else if (tempFormat == JMU)
{
if (exchange == OFFICE) result = "x8-";
else if (exchange == DORM) result = "x2-";
result += fourDigitExtension;
}
return result;
}
Modify your driver so that it can be used to test the
toString() methods.
Execute your driver and test these methods.
Add an implementation of the following equals() method
to the JMUPhoneNumber class.
/**
* Determine if this JMUPhoneNumber has the given
* areaCode, exchange and extension
*
* @param areaCode The area code
* @param exchange The exchange
* @param extension The extension
*/
public boolean equals(int areaCode, int exchange, int extension)
{
}
solution/JMUPhoneNumber.java
(Fragment: equals3)
/**
* Determine if this JMUPhoneNumber has the given
* areaCode, exchange and extension
*
* @param areaCode The area code
* @param exchange The exchange
* @param extension The extension
*/
public boolean equals(int areaCode, int exchange, int extension)
{
return (this.areaCode == areaCode)
&& (this.exchange == exchange)
&& (this.extension == extension);
}
Modify your driver so that it can be used to test the
equals() method.
Execute your driver and test this method.
Modify the 1-parameter version of the equals() method
so that it calls the 3-parameter version of the equals()
method. (Changing a method without changing its external behavior is
caused refactoring.)
solution/JMUPhoneNumber.java
(Fragment: equals1)
/**
* Determine if this JMUPhoneNumber has the same
* areaCode, exchange and extension as the given JMUPhoneNumber
*
* @param other The other JMUPhoneNumber
*/
public boolean equals(JMUPhoneNumber other)
{
return equals(other.areaCode, other.exchange, other.extension);
}
Execute your driver and test this method. (Running existing tests to
ensure that changes have not introduced any defects is called
regression testing.)
Why should one version of the equals() method call the
other version?
To avoid code duplication.
One could implement these methods differently and have the
the 3-parameter version of the equals()
method call the 1-parameter version. Why would this be a bad idea?
In other words, why should the 1-parameter version of the
equals()
method call the 3-parameter version? Or, put still another way,
what would the 3-parameter version have to do in order to call
the 1-paremeter version?
The 3-parameter version would have to construct a JMUPhoneNumber
object with the given area code, exchange, and extension. That object
would then not be used for anything else and would have to be
garbage collected. In general, this kind of thing should be
avoided if possible.
Why is the 1-parameter version of the equals() method
able to access the areaCode, exchange,
and extension attributes of other
when they are private?
The definition of private is subtle in Java. Attributes
and methods that are declated
private are actually accessible to all objects in the class,
not just the owning object. This can be dangerous!
2. Overloading Constructors:
This part of the lab will give you some experience writing overloaded
constructors.
Overload the constructor with a new version that is passed
the exchange, extension, and format.
/**
* Explicit Value Constructor
*
* @param areaCode The area code
* @param exchange The exchange
* @param extension The extension
* @param format The format
*/
public JMUPhoneNumber(int areaCode, int exchange, int extension,
int format)
{
this.areaCode = areaCode;
this.exchange = exchange;
this.extension = extension;
this.format = format;
}
Modify the default constructor so that it calls the explicit
value constructor you just wrote.
/**
* Default Constructor
*
* Constructs a JMUPhoneNumber with the areaCode set to 540,
* the exchange set to 568, the extension set to 6211, and the
* format set to JMU
*/
public JMUPhoneNumber()
{
this(540, 568, 6211, JMU);
}
Modify your driver so that it can be used to test these constructors.
Execute your driver and test these constructors.
Write another constructor that is passed just an extension. This
version should assume that the area code is 540, the exchange is
OFFICE and that the format is US_OLD.
(This constructor should call another constructor in the same
class.)