|
|
CSCI 201
Introduction to Algorithm Design home | homework index | labs index |
SPRING 2007 |
An object is an entity that lives in the heap. It is created from a class while your program is running. Objects contain instance variables, which encode object properties, and instance methods, which act on those properties.
When you write a java program, you write
classes. In general, a class is a
template for making objects: each object can be thought of as
a realization of a class. The class defines both the instance
variables and the methods of the object. The process of
creating a new object from a class is called
instantiation. You use the keyword
new to
instantiate an object.
For example, the code:
new myClass();
would create an object in the heap from the
class myClass and then return a reference to
that object. Unfortunately, Java can't refer to
things in the heap by a name. After an object is created, the
system forgets where it is. So, in order to use objects, we
must store their locations in reference
variables.
Simply put, a reference variable stores
an address of an object and thus
serves as the object's name.
Very simple values, like integers and doubles,
are not objects. They are
primitive data types. You can think of
primitive variables as storing data,
and reference variables as storing links to data.
Creating reference
variables is just like creating primitive variables. When you
create a new reference variable, it links to nothing. You can make
it link to an object by assigning it
the value returned by
new. Pretend we have a class called
intHolder which looks like this:
class intHolder {
private myInt;
public intHolder (int newInt) {
myInt = newInt;
}
public int getInt() {
return myInt;
}
}
The following Stack N' Heap demonstrates the difference between primitive and reference variables.
|
Code
int prim = 5;
intHolder ref = new intHolder(5); System.out.println( "prim = " + prim ); System.out.println( "ref.getInt() = " + ref.getInt() ); |
Stack
|
Heap
|
|
Temporary
|
Objects can have both state and
behavior. The state of an object is
maintained in instance variables while
instance methods provide the behavior.
Suppose you had two intHolder objects, one called
bi which has 2
in its instance variable, and one called
tri which has 3
in it's instance variable. If you typed the command:
bi.getInt();
you would run the instance method
getInt in the
bi object. This would return the
number 2.
Unlike instance variables and methods,
static variables and methods are
not part of any object. They are associated
with the object's class.
When you create a static
variable, only one copy of that variable will ever exist in
memory. The same is true for a static method. When you
call a static method or use a static variable, you give the
name of the class first, followed by a
period, and then the name of the static method or variable. For
example, lets say that the intHolder class has a static
variable called maxValue.
The definition for it might look like this
inside the class:
public static int maxValue = 3000;
To access the maxValue variable from any place in your
program, you would type
intHolder.maxValue. Because there can
be only one class called intHolder in
your program, there is also only one variable called
intHolder.maxValue. Any intHolder
object that you instantiate from this class would
not have its own maxValue. However, you can
access the intHolder.maxValue variable from within
instance methods, just as you would from anywhere
else in your program.
Static variables are generally used for constants that
are appropriate for all objects of the class.
Public static variables are also appropriate for widely
used program constants, such as Color.BLUE
and System.in.
Assigning to a static variable is an extreme measure.
The most famous static method is main, the
entry point for Java applications.
Static methods are also appropriate for object independent
collections of routines,
such as Math.pow
and Math.sin.
Because static methods are required to have the same behavior for
all instances of a class, they are not allowed to even reference,
let along modify, a non-static instance variable.
This restriction can make the writing of a static method a real
challenge. It's best to avoid them -- except for main.
When we first instantiated the intHolder object using
new, you may have noticed that we
placed a number in parenthesis following the class name:
intHolder ref = new intHolder ( 5 );.
This number is passed to the intHolder object's
constructor. A constructor is the
first method that is run when an object is instantiated. The
intHolder's constructor is:
public intHolder (int newInt) {
myInt = newInt;
}
To write a constructor, you write a method that has no return type and whose method name the same as the class name. Most constructors look like the one shown above. They receive a collection of parameters which are copied into instance variables. These copies must be made. Otherwise, the parameter value will be lost when the constructor completes.
The constructor, like the one above, is "called" by using
the Java keyword new as shown below:
intHolder ref = new intHolder(5) ;
When this statement is executed, the Java system allocates new
space for the intHolder object and transfers to
the intHolder constructor which should initialize
the instance variables of the object.
When new is used to construct an object,
it must use a matching constructor. For example,
new intHolder(3.1416) is not allowed.
This new intHolder tries to use a double
to construct the object, but the constructor only accepts an int.
Similarly, both new intHolder() and
new intHolder(6, 7) will fail.
One has too few parameters, and the other has too many.
Frequently, a class is defined with multiple constructors, in which
case new will succeed if it finds a matching constructor.
For example the following constructor, which gives myInt
a default value of 0, would match new intHolder().
public intHolder () {
myInt = 0;
}
You can even match
new intHolder(3.1416) by including the
followig constructor.
public intHolder (double newNearInt) {
myInt = Math.round(newNearInt);
}
Download Forest.zip, a ZIP file containing a NetBeans project named
Forest and unZIP this project
into your csci/201 directory.
Try to make your Projects panel look
something like the following picture before continuing.
This is another lab that uses our FrameMaker class.
There is a Main class within the forest package
that calls
FrameMaker to create a frame containing the
panel created within Forest.java.
If you dig deeper into your project, you will also find a
class called Triangle within the
edu.unca.cs.csci201.labaids package.
In this lab, you will modify Forest.java
and also create a new class called Tree.
You should not modify Main.java
or Triangle.java during the lab.
The code for the Triangle class of
edu.unca.cs.csci201.labaids is shown below.
Notice how the state of a triangle is "remembered"
in two instance variables, one for the triangle's color and
another for its endpoints.
Look at the constructor for Triangle and see
how its parameters x, y,
length, and c are used to
initialize the instance variables color and
triangle.
package edu.unca.cs.csci201.labaids;
/**
* Creates and draws an upwarding pointing triangle.
*/
public class Triangle {
// instance variables
private java.awt.Color color;
private java.awt.Polygon triangle;
// methods
/**
* Constructs the triangle
* @param x X co-ordinate of the top vertex of the triangle
* @param y Y co-ordinate of the top vertex of the triangle
* @param length Length of a side of the triangle
* @param c Color of the triangle
*/
public Triangle(int x, int y, int length, java.awt.Color c) {
int[] xpoints = {x, x-length/2, x+length/2};
int[] ypoints = {y, y+(int)(0.866*length), y+(int)(0.866*length)};
triangle = new java.awt.Polygon(xpoints, ypoints, 3);
color = c;
}
/**
* Draws the triangle
* @param g Graphics object for drawing the triangle
*/
public void draw(java.awt.Graphics g) {
java.awt.Graphics copyG = g.create() ;
copyG.setColor(color);
copyG.fillPolygon(triangle);
}
}
Now study the comments of this code for a moment.
You should notice that the comments seem to conform to a
strong, but rather unreadable, convention. It's as if they were intended for
digital, rather than, human consumption.
In fact, the comments were written so the
javadoc program can use them to
generate some nice web pages.
You should now read the
Java documents file for Triangle
to see the nicely formatted method descriptions.
You'll need to use these methods to
complete the lab.
Now take a look at Forest, our swing component class.
This class, in its incomplete state, contains one instance variable,
triTop. It also contains code to initialize
and draw this object.
Now a forest has trees and trees sort of look like a bunch of triangles.
Right?
We're going to do this lab in three steps.
In the first step, you will modify your Forest class to
draw a single tree composed of three triangles.
In the second step, you move the code for drawing a single tree
into its own class which will be called directly by Forest.
In the third step, you'll add trunks to your trees.
Got it? Good.
First let's work on the instance variables.
We need to create a tree from three triangles.
Since the Triangle class is within the
edu.cs.unca.csci201.labaids package,
our code for the Forest class contains
a line to import the
edu.cs.unca.csci201.labaids.Triangle package.
Now we must add declarations for two more instance variables, call
them triMiddle and
triBottom.
These declarations should be within the
code for the Forest class, right after
the declaration for triTop.
We must also initialize the three triangles to reasonable values.
If you look at the Public constructor, you will see
that triTop is already initialized.
You need to add assignment statements to initialize the
triMiddle and triBottom objects.
Now you must draw the tree. Within the paint
method of Forest, there is already a call to draw
the triTop method.
Add calls to the draw
methods of the other two triangles. Now run
your program.
We suggest that you keep the tree modestly sized, perhaps half the size of the frame, because you will want to paint several trees a bit later in the assignment.
If you don't see any triangles, make sure that your triangle is being created within the bounds of your frame. If you see only one or two triangles, it is likely that a big triangle is covering a smaller one. In this case, you should experiment with making the triangles different colors and drawing the big triangles before the small ones. If you see a little red triangle inside a big blue triangle, you need to work on your triangles' positions and sizes.
Once you have your three triangles displayed in a pretty fashion, ask the lab instructor for a check-off. Do not be surprised if the lab instructor asks you to modify your arrangement to fit the demands of the remainder of the lab.
We want forests, not trees. We could keep adding more
triangles to Forest, but a tree is a real-world
object, and real objects deserve Java objects.
So create a new file with the following steps:
Tree and place it in the
forest package.
Now here's the hard part.
Tree class.Forest class into
your Tree class.Forest to Tree.Forest to Tree. At this point, you should stop seeing the red lines.import edu.unca.cs.csci201.labaids.Triangle ; statement. You should see a lot of new red lines.paint method in your new Tree class, and change the name of this method to draw. (We know this seems silly, but we're just following Java's naming convention for graphical objects.)extends javax.swing.JComponent modifier from the class defintion for Tree.setPreferredSize call from the Tree constructor.
Just
making these simple (HA!) changes should create a working
Tree class that can be used to draw a single tree.
Don't get impatient. Just work through these changes until
you are able to successfully build your application.
Do not proceed past this point until you are
able to build the new Tree class.
You can now run your application,
but it won't be using your Tree
because Forest still creates its own
Triangle objects and never uses any Tree object.
We must fix this.
Go to Forest.java and everytime you
see Triangle, replace it with Tree.
This will cause a problem where you try to initialize a
Tree object with a constructor like
new Tree(200, 50, 100, Color.GREEN),
because the Tree constructor has no parameters
while the Triangle constructor had four parameters.
To fix this, just remove the parameters to the Tree
constructor, as in new Tree().
Once you are done, you can build and run your program. The display of your program should not change since all three trees are being drawn at the same location.
When you have Tree engaged, show your
instructor your lonesome pine.
We need to spread out the trees.
The problem is that all trees are constructed with same properties.
Start by adding the following empty constructor to
your Tree class.
public Tree(int x, int y, java.awt.Color c) {
}
Those parameter names should look familiar. You should have seen them
in the code for the Triangle class.
Now fill in the new constructor to use these parameters to
"personalize" your tree.
The new constructor should be very similar to the old.
In fact, you should start this process simply by copying the
body of the old new Tree constructor into
the new new Tree constructor.
The only difference will be the parameters to the
Triangle constructor. Now they should depend
on x, y, and c,
the parameters to your new Tree constructor.
Once you've been able to build your project with the modified
Tree class, turn your attention to the Forest.
Modify your Forest.class
to use the new new Tree
to create three trees of different colors at different positions
within the screen.
To do this, you must make sure that the Tree constructor
is being called with three parameters, two integers and a color.
Show your instructor the three tree forest.
Real trees have trunks. Your final task is to add some
tree trunks as shown in the following picture.
You know how to do the graphics.
You must call the setColor method of Graphics
to choose a suitable trunk color (such as color.DARK_GRAY),
and then you must use fillRect to draw the rectangle
representing the trunk.
However, you must also add new instance variables to Tree
to remember the trunk position. That's the hard part.
Complete the forest and show your instructor your work.
Last modified: 03/29/07