CSCI 201 Introduction to Algorithm Design
home | homework index | labs index 
SPRING 2007  

Objects

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.

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

Parts of an Object

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.

Static

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.

Constructors

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.

Invoking the constructor

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);
}	

Downloading the project framework

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.
Initial project panel

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.

The assignment -- at last

The plan

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.

The single tree forest

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.
One tree

In case of trouble

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.

Creating a new class

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:

  1. Use the File → New File... menu choices to bring up the New File window dialog.
  2. Choose file type Java class within category Java classes.
  3. Name your new class Tree and place it in the forest package.

Now here's the hard part.

  1. Delete everything in your newly created Tree class.
  2. Copy the contents of your Forest class into your Tree class.
  3. Change the name of the class from Forest to Tree.
  4. Change the name of the class constructor from Forest to Tree. At this point, you should stop seeing the red lines.
  5. Delete the import edu.unca.cs.csci201.labaids.Triangle ; statement. You should see a lot of new red lines.
  6. Find the 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.)
  7. Remove the extends javax.swing.JComponent modifier from the class defintion for Tree.
  8. Remove the 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.

Displaying a real forest

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.
Three trunk-less trees

Show your instructor the three tree forest.

Your forgot your trunks

Real trees have trunks. Your final task is to add some tree trunks as shown in the following picture.
Three trees

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    

Please Provide Feedback. We will use this information to improve the CSCI 201 Labs.