An object is a 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 realzation 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 referenceto
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 object. They are
primitive data types. You can think of
primitive variables as storing data,
and reference variables 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 a 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 assoiated
with the object's cass.
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 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 reference 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
.
Similary, 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 construtor, 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 costructor.
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.
There may be a
Test Packages in your project.
Don't worry about it.
This is another lab that uses our FrameMaker
class.
There is a "main" class, ForestMain
, 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 ForestMain.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 format method desciptions.
You'll need to use these methods to
complete the lab.
Now take a look at Forest, our applet 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.
We must also initialize the three triangles to reasonable values.
This is done by calling the Triangle
constructor
three times within the Forest
constructor.
Now you must draw the tree. Within the paint
method of Forest
, add calls to the draw
methods of each of your three 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 arrangment 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
.
Now here's the hard part.
Copy the contents of your Forest
class into
your Tree
class and change the names of its
constructor and single method.
Change the name of the constructor from Forest
to Tree
, and change the name of the paint
method to be draw
.
You must also be sure to copy the two import
statements into the Forest
class.
There are also some other minor touchups.
The Tree
class should not extend the
javax.swing.JComponent
class, and the Tree
constuctor should not
call the setPreferredSize
methods.
Just
making these simple 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 isn't using your Tree
because Forest
still creates its own
Triangle
objects and never uses a Tree
object.
We must fix this.
Go to Forest.java and replace
the three Triangle
's with three Tree
's.
This will involve changing declarations and even removing
parameters to constructor calls because
the Tiangle
constructor has four parameters
and the Tree
constructor has no parameters.
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
instuctor your lonesome pine.
We need to spread out the trees.
The problem is that all trees are constructed with same properities.
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 familar. 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.