[Instructions] [Search] [Current] [Syllabus] [Links] [Handouts] [Outlines] [Labs] [More Labs] [Assignments] [Quizzes] [Examples] [Book] [Tutorial] [API]
Some subtle (and not-so subtle) notes:
x,
y, and z. However, given the ellipses,
it is possible anything could have happened. (I've updated the
instructions to clarify this.)
PointFun so I didn't need to
recompile it''. In many languages, if any library changes, you
must recompile (or relink) the whole program.
computer.average(int,int),
it is able to use
computer.average(double,double).
This is because Java will automatically promote integers
to doubles.
Consider the following fragment of Java code
int x = 0; int y = 0; int z = 0; ... // position 1 (before the following steps) x = 2 * y; y = 5; z = x + y; // position 2 (after the first set of steps) x = 2 * y; y = 5; z = x + y; // position 3 (after both sets of steps)
What are the values of x, y, and
z at positions 1, 2, and 3?
You do not know the values of x, y, and
z at position 1, before the first set of steps. (Since
each could have been given a different value in the intervening code.)
At position 2, you still don't know the value of x or
z (which depends on x). However, the value
of y must be 5.
At position 3, x is 10, y is 5, and
z is 15.
If you decided that nothing happened to
x, y, and z
between initialization and
position 1, then all three have the value 0 at position 1;
x=0, y=5, and z=5 at position 2; and
x=10, y=5, and z=15 at position 3.
Required code files:
Step 1.
Make copies of the required code files. Modify
PointPrinter.java so that it includes a
numprinted
field which it prints and updates every time it prints a point.
Modify PointFun.java so that it creates and uses a
PointPrinter object for output. Compile the various files,
execute PointFun, and record the results. Are they what
you expected? Why or why not?
Yes, the results are what I expected. Each point is preceded by the
number of the point. Here are the lines that I added to
the print method of PointPrinter.
// Update our count. Added in Step 1 of J3.2.
this.numprinted = this.numprinted + 1;
// Print the number of the point. Added in Step 1 of J3.2.
out.print(this.numprinted + ": ");
Note that the first number printed is 1. That is because the default
initialization of numprinted is 0.
Step 2.
Rename numprinted to printed everywhere
that it appears in PointPrinter.java and recompile.
Execute PointFun and record the results. Are they what you
expected? Why or why not?
Yes, the results are what I expected. What we name a field should not matter, as long as we are uniform in our naming (and don't use a keyword). This is an instance of the power of information hiding. Since other classes don't know what you've named the field, changes to the field don't affect the operation of your program.
Step 1.
Create a new class, MyPoint, that contains two integer
fields, xcoordinate and ycoordinate. Note
that all you will need for this class (at least at this point) are the
class declaration and the field declarations. Compile your class and
correct any errors reported by the compiler. Enter the code for your
class here.
/**
* Points on the plane, using integer coordinates.
*
* @author Samuel A. Rebelsky
* @version 1.0 of February 1999
*/
public class MyPoint {
// +--------+--------------------------------------------------
// | Fields |
// +--------+
/** The x coordinate. Surprise surprise. */
protected int xcoordinate;
/** The y coordinate. Surprise surprise. */
protected int ycoordinate;
} // class MyPoint
Step 2.
Create a print(SimpleOutput out) method for your
MyPoint class. This method should print out the point in a
reasonable format. Recompile your class and correct any errors reported
by the compiler. Enter the code for that method here.
/**
* Print the current point, using something that knows how
* to print integers.
*/
public void print(SimpleOutput out) {
out.println("(" + this.xcoordinate + "," + this.ycoordinate + ")");
} // print(SimpleOutput)
Step 3.
Create a TestMyPoint class with a
main method that creates a MyPoint and asks it
to print itself out. Compile and execute TestMyPoint.
What values are printed for the x and y coordinates? Why do you think
this is?
Here is the main method, using two kinds of printing.
The note at the end of the lab should describe the differences.
public static void main(String[] args) {
// Build a point.
MyPoint mypt = new MyPoint();
// Build something that knows how to print.
SimpleOutput out = new SimpleOutput();
// Print, using the incorrect method. Since
// out doesn't know anything about points, who
// knows what we'll get.
out.println(mypt);
// Print, using the correct method. Since points
// know how to use output objects, we should get
// something reasonable (but what?)
mypt.print(out);
} // main(String[])
The values printed for the x and y coordinates are 0 and 0. Why? We didn't give any values, so the Java compiler chose ``reasonable'' defaults. (Any time you don't explicitly initialize an integer field, it gets initialized to 0.)
Step 4. Create a setLocation(int x, int y)
method for the MyPoint class. This method will set the
xcoordinate and ycoordinate fields to the
corresponding parameters. Recompile MyPoint and correct
any compiler errors.
Extend TestMyPoint to test this method by setting the x
coordinate to 2 and the y coordinate to 3 and then asking the point to
print itself. Recompile and run TestMyPoint and correct
any errors.
Enter the code for the setLocation method here.
/**
* Set the x and y coordinates.
*/
public void setLocation(int x, int y) {
this.xcoordinate = x;
this.ycoordinate = y;
} // setLocation(int,int)
Required code files:
Point.java
PointFun.java
(as modified in experiment J3.2).
PointPrinter.java
(as modified in experiment J3.2).
Step 1.
Create a constructor for the PointPrinter class that takes
no parameters and initializes any fields to appropriate values.
Recompile PointPrinter and execute PointFun.
What happens? Is that what you expected? Why or why not?
/**
* Create a new printer, initializing the count of printed points
* to 0.
*/
public PointPrinter() {
this.printed = 0;
} // PointPrinter()
Exactly the same thing happened as before. Since the default is to initialize an integer field to 0, this doesn't seem to do much.
Step 2.
In step 1, we recompiled PointPrinter but
execute PointFun. Why didn't you need to recompile
PointFun?
PointFun did not change. Since Java only loads classes
when needed, when we run PointFun it loads the current
version of PointPrinter.
Step 3.
Create a one-parameter constructor for the PointPrinter
class that initializes the count of points printed. Update
PointFun to use that constructor and to use 100 as the
first value. Recompile and test. Enter your code for the constructor
here.
/**
* Create a new printer, initializing the count of printed points
* to the given value.
*/
public PointPrinter(int init) {
this.printed = init;
} // PointPrinter(int)
Step 4.
Update PointFun to use the zero-parameter constructor.
Recompile and test. What happens? Is that what you expected? Why or
why not?
Not so surprisingly, the results are the same as in the first step. It runs, using 0 as the initial value.
Step 5.
Delete the zero-parameter constructor for the PointPrinter
class (leaving you with just the one-parameter constructor). Recompile
PointPrinter and try to execute PointFun (you
should not need to recompile PointFun). What happens? Is
that what you expected? Why or why not?
Hmmm .... it won't run. I get the completely unreadable error message of
java.lang.NoSuchMethodError: PointPrinter: method <init>()V not found
at PointFun.main(PointFun.java:17)
Why won't it run? Because there is no 0-parameter constructor, and
we've tried to use one. What happens if we try to recompile
PointPrinter? We get the same error, but in a
slightly different form.
PointFun.java:19: No constructor matching PointPrinter() found in class PointPrinter.
PointPrinter printer = new PointPrinter();
Step 6.
Delete the one-parameter constructor for the
PointPrinter class (leaving you with no constructors).
Recompile PointPrinter and try to execute
PointFun (you should not need to recompile
PointFun, but you may do so if you wish). What happens?
Is this the same as in the previous step? Why or why not?
It runs! (It also compiles!) That's strange, isn't it. The explanation is that when you don't give any constructor, Java creates a `default' constructor. However, when you give a constructor, Java no longer assumes the default constructor.
Required code files:
MyPoint.java
(created in experiment J3.3)
TestMyPoint.java
(created in experiment J3.3)
Step 1.
Create a constructor for the MyPoint class that takes two
parameters: the initial x value and the initial y value. Recompile
MyPoint and correct any errors.
Update TestMyPoint to use that constructor (and only that
constructor). For example, you might write
MyPoint pt = new MyPoint(2,3);
Recompile and run TestMyPoint.
Enter your code for the constructor here.
/**
* Create a new point with given x and y coordinates.
*/
public MyPoint(int x, int y) {
// Take advantage of the function we've already written.
this.setLocation(x,y);
} // MyPoint(int,int)
You might also use
public MyPoint(int x, int y) {
this.xcoordinate = x;
this.ycoordinate = y;
} // MyPoint(int,int)
Step 2.
Update TestMyPoint to use a parameterless constructor for
MyPoint. For example, you might write
MyPoint pt2 = new MyPoint();
What happens when you try to compile and run TestMyPoint? Why?
You get a ``no such constructor'' error message. Why? Because there is no zero-parameter constructor, and you're trying to use one.
Step 3.
Create a parameterless constructor for MyPoint that
initializes both coordinates to 0. Recompile MyPoint and
correct any errors. What happens when you try to compile and run
TestMyPoint? Is your result the same as or different from
the result in Step 2? Why?
/**
* Create a new point initialized to (0,0).
*/
public MyPoint() {
this.setLocation(0,0);
} // MyPoint
I am now able to compile and run TestMyPoint. This is
different than in the previous step. It was expecting a constructor,
and now there is noe.
Step 4.
Make a copy of MyPoint named MyPt (when making
the copy, you will need to change the file name to
MyPt.java and the class name to MyPt). Try to
compile the new class. What happens? Why? How can you correct that problem?
We now get error messages about the constructors because they no longer have the same name as the class, and are therefore interpreted as normal functions, which therefore need return values. We should rename the constructors.
Required files:
Point.java
PointPrinter.java
(if you've modified this in a previous part of this
lab, do not make another copy)
PointReader.java
ReadTester.java
Step 0.
Make a copy of Point.java, PointReader.java and
PointPrinter.java. Compile
the three files.
Step 1.
Make a copy of ReadTester.java.
Compile and execute ReadTester. Record the output.
Enter the x coordinate: 2 Enter the y coordinate: 3 1: (2.0,3.0) distance from origin: 3.605551275463989
Whop de doo!
Step 2.
Add the following lines to the main method of
ReadTester.
// Step 2. Read a point without prompting.
pt = reader.read(in);
printer.print(out,pt);
What do you expect to happen when you compile this modified class?
There is no read(SimpleInput) method in the
PointReader class, so I'll get an error.
Step 3.
Attempt to compile the modified ReadTester. Record any errors.
What do these errors suggest?
ReadTester.java:23: Wrong number of arguments in method.
pt = reader.read(in);
Just as we've guessed, there is no corresonding method in the
PointReader class.
Step 4.
Add the following method to PointReader.
/**
* Read a point without prompting.
*/
public static Point read(SimpleInput in) {
float x; // The x coordinate.
float y; // The y coordinate.
x = in.readFloat();
y = in.readFloat();
return new Point(x,y);
} // read(SimpleInput)
What do you expect to happen when you compile this modified class?
It should compile without any errors. Sometimes things go okay.
After entering your answer, compile the modified class and correct any errors.
Step 5.
What do you expect to happen when you now try to compile
ReadTester?
It should now compile without any errors, since the requisite method
is now in PointReader.
After entering your answer, compile the modified class.
Step 6.
Execute ReadTester and record the results. Note that you
will have to enter the two components of the second point without being
prompted.
Enter the x coordinate: 2 Enter the y coordinate: 3 1: (2.0,3.0) distance from origin: 3.605551275463989 2 3 2: (2.0,3.0)
Required files:
AverageComputer.java
(created in a previous laboratory).
AverageTester.java
Step 0. Make sure you have a fresh copy of
AverageComputer.java,
which you should have created in a previous lab.
Also make sure that you have a copy of
AverageTester.java.
Step 1. Compile the two files and execute
AverageTester. When prompted for input, enter 2 and 3
and record the results.
Enter a number: 2 Enter another number: 3 The average of 2.0 and 3.0 is 2.5
Step 2.
Add the following lines to the end of the main
method of AverageTester.
// Step 2. Average two integers.
int firstInt;
int secondInt;
out.print("Enter an integer: ");
firstInt = in.readInt();
out.print("Enter another integer: ");
secondInt = in.readInt();
out.println("The average of " + firstInt + " and " + secondInt +
" is " + computer.average(firstInt,secondInt));
What do you think will happen when you try to compile and execute
the modified AverageTester?
It will once again print that the average is 2.5. I have some
worry that the parameters to average are supposed
to be doubles, and I'm using ints.
Step 3.
Compile and execute the modified AverageTester, using 2 and
3 as the pair of numbers in each case. Record and explain the output.
Enter a number: 2 Enter another number: 3 The average of 2.0 and 3.0 is 2.5 Enter an integer: 2 Enter another integer: 3 The average of 2 and 3 is 2.5
Although average expects two doubles,
Java knows how to convert ints to doubles.
I've also observed a small difference in the two outputs. In the second
case, the output read 2 and 3 rather than
2.0 and 3.0. That's because the things being printed
are integers rather than reals.
Step 4.
Add the following lines to the end of the main method of
AverageTester.
// Step 4. Compute the average in a different way.
out.print("That average might also be stated as ");
out.println((firstInt + secondInt) / 2);
What do you expect the new output to be?
At first guess, I'd expect it to be the same as in the past: 2.5. (I'd be wrong, though.)
Step 5.
Compile and execute the modified AverageTester, using 2 and
3 as the pair of numbers in each case. Record and explain the output.
Enter a number: 2 Enter another number: 3 The average of 2.0 and 3.0 is 2.5 Enter an integer: 2 Enter another integer: 3 The average of 2 and 3 is 2.5 That average might also be stated as 2
In that final computation, it must be doing integer division, in which case it rounds down.
Step 6.
Add the following method to AverageComputer.
/**
* Compute the average of two integers.
*/
public int average(int a, int b) {
return (a + b) / 2;
} // average(int,int)
Do you expect this modification to have any effect on the output of
AverageTester?
Yes. Before I was calling average(double,double),
with the integers being converted. Now I will be calling this new
version of the method.
Step 7.
Recompile AverageComputer and AverageTester.
(Even though you have not modified AverageTester, you should
recompile it because you've overloaded a method it uses in AverageComputer.)
Execute AverageTester.
Enter 2 and 3 for each pair of numbers. Record your output. Does this output
differ from that in step 5? If so, why?
Enter a number: 2 Enter another number: 3 The average of 2.0 and 3.0 is 2.5 Enter an integer: 2 Enter another integer: 3 The average of 2 and 3 is 2 That average might also be stated as 2
Clearly, there's a difference. Now, when we average 2 and 3 we get 2, rather than 2.5. This is because the new method is being used.
As a side note, I checked what happened if I only recompiled
AverageComputer and not AverageTester.
We still use average(double,double) method, because
that's all that AverageTester knew about when it was
compiled.
Step 8.
Remove the average(int,int) method from
AverageComputer. Then
add the following methods to AverageComputer.
/**
* Compute the average of an integer and a double.
*/
public double average(int a, double b) {
return (a + b) / 2;
} // average(int,double)
/**
* Compute the average of a double and an integer.
*/
public double average(double a, int b) {
return (a + b) / 2;
} // average(double,int)
Do you expect this modification to have any effect on either program?
It doesn't seem that the modification should have any great effect, but I've been known to be wrong in the past.
Step 9.
Compile AverageComputer. If that succeeds, compile
AverageTester. If that succeeds, execute
AverageTester. What happened? Why?
AverageTester.java:43: Reference to average is ambiguous. It is defined in double average(double, int) and double average(int, double).
" is " + computer.average(firstInt,secondInt));
Clearly, Java can't decide what to do. There are two different methods
that come close to matching average(int,int) and it
has no way to decide which to use.
[Instructions] [Search] [Current] [Syllabus] [Links] [Handouts] [Outlines] [Labs] [More Labs] [Assignments] [Quizzes] [Examples] [Book] [Tutorial] [API]
Disclaimer Often, these pages were created "on the fly" with little, if any, proofreading. Any or all of the information on the pages may be incorrect. Please contact me if you notice errors.
This page may be found at http://www.math.grin.edu/~rebelsky/Courses/CS152/99S/Assignments/notes.02.html
Source text last modified Tue Aug 10 10:15:11 1999.
This page generated on Tue Aug 10 10:15:20 1999 by SiteWeaver. Validate this page's HTML.
Contact our webmaster at rebelsky@math.grin.edu