Activity #3: Objects and Components
by Steve Hirst
12 Sept 97
There is quite a bit of content in this activity and its things I see a
lot of questions on in internet news groups. So, bear with me.
Objects constructors, finalizers and reference
First, the object model. Just like C++, Java has a notion of class,
object, class and object fields, and object references. Classes are programmer
defined types; the values that correspond to the types are objects. Unlike
C++, however, when I declare a class MyClass and then a variable
typed by the classname (i.e. MyClass oneObject; ) an object of
type MyClass is not created; instead, the variable oneObject
is initializialized to a null reference. Strictly speaking all object
variables are reference variables and all objects must be dynamically created
with the new operator. Look at the following code snippet:
Cloning Class
// Cloning: demonstrate reference and clone
// Steve Hirst
// $Id: Cloning.java 1.1 1997/09/12 03:29:19 Steve Exp Steve $
package activity;
public class Cloning implements Cloneable {
private int value;
public int getValue() { return value; }
public void setValue(int newValue ) {
value = newValue;
}
public Object clone() {
Cloning copy = new Cloning();
copy.setValue(getValue());
return copy;
}…
|
The class Cloning has three public methods defined: getValue(),
setValue(int) and clone(). The methods setValue and getValue
allow for the setting and getting of the private integer field. As
in C++, a default constructor is generated by the system. Consider the
following code:
What happens here:?
Cloning one,two,three,four;
one = new Cloning();
one.setValue(42);
two = one;
two.setValue(47);
three = new Cloning();
three.setValue(24);
four = (Cloning) three.clone();
four.setValue(74);
System.out.print("One = ");
System.out.println(one.getValue());
System.out.print("Two = ");
System.out.println(two.getValue());
System.out.print("Three = ");
System.out.println(three.getValue());
System.out.print("Four = ");
System.out.println(four.getValue());
System.out.println("======================");
|
Activity: Figure out the values for one,two, three and four.
Write up a quick java program to test your answer. If you haven't
noticed before, java does not have global variables or functions.
You will need to define a main proc. attached to some class; you can add
the above code as a static main method in the class clone.
Passing reference parameters by value.
Unlike C++, java passes all parameters by value. That means that assignments
to parameter variables do not effect the actual arguments. However,
call a method on an object may change that object and change the behavior
in all the places that object is referred to (i.e. the calling environment).
Try the following method to see this in action:
shuffle
static void shuffle(Cloning arg1, Cloning arg2,
int arg3, int arg4) {
arg1 = arg2; // arg1 passed by value; no change to actual1
arg1.setValue(99); // arg1 and arg2 both refer to same
// object as actual2
arg3 = arg4; // arg3 passed by value no change to intActual1
arg4 = -2; // ditto
}
|
Class vs. Object members
If you put the keyword static in front of a member declaration,
it is a class member. There is always exactly one instance
of a class member independent of how many (including zero) objects exist
of that type. So, if you declare a class:
Util
class Util {
static int screenWidth;
public static void setScreenWidth(int width ) { screenWidth=width; };
public static int getScreenWidth() { return screenWidth; };
int cursorPosition=0;
public void moveLeft()
{ ++cursorPosition;
if (cursorPosition>=screenWidth) cursorPosition=0;
}
public int getCursorPostion() {return cursorPosition; };
}
|
The members screenWidth, setScreenWidth, and getScreenWidth are all
class members. They can be referred to as Util.screenWidth,
Util.setScreenWidth(23) and Util.getScreenWidth(); however referencing
an object member would be illegal (for example, Util.moveLeft() ).
Also if we have the following code:
Using Util
Util one = new Util();
one.setScreenWidth( 80 );
System.out.println(util.getScreenWidth());
|
will output 80. Also the following is illegal:
Illegal reference to non-static member
public static void setScreenWidth(int width ) {
screenWidth=width;
if (cursorPosition>=screenWidth) cursorPosition = 0;
};
|
Garbage collection and finalization
Because all objects are dynamically created in java, they must all be destroyed.
However, java does not have a delete operator or the concept of a destructor.
Instead, the java runtime uses garbage collection to recover unreference
memory locations. You can define a finalize method.
The following defines a class Thing which keeps track of how many objects
of type Thing have been created and exits when the 20th object created
is finalized:
Thing
class Thing {
private static int counter=0;
private int index;
public Thing() {
index = ++counter;
if (index==100)
System.out.println("Hundredth thing served.");
}
public static int numberCreated()
{ return counter; }
public void finalize() {
System.out.print("Finalizing thing #");
System.out.println(index);
if (index==20) {
System.out.print( counter );
System.out.println(" things created.");
System.exit(1);
}
}
}
|
The following code creates a lot of garbage:
Garbage
Thing aThing;
int loopCount = 0;
while (true) {
aThing = new Thing();
switch (++loopCount) {
case 4:
case 12:{
System.out.print("Calling runFinalization after creating ");
System.out.print( Thing.numberCreated() );
System.out.println(" things.");
System.runFinalization();
System.out.println("---- end of finalization ---");
break;
}
case 8: {
System.out.print("Calling gc after creating ");
System.out.print( Thing.numberCreated() );
System.out.println(" things.");
System.gc();
System.out.println("---- end of finalization ---");
break;
}
case 16: {
System.out.print("Calling gc before runFinalization after creating ");
System.out.print( Thing.numberCreated() );
System.out.println(" things.");
System.gc();
System.runFinalization();
System.out.println("---- end of finalization ---");
break;
}
}
}
|
What the hell...
does this code do? First the working part the loop is basically:
while(true) { aThing = new Thing(); ... }. Everytime through
the loop the reference to the previously created Thing is replaced by a
new one; this makes the previous object into garbage. If you write
a loop that does nothing more than this, it will eventually fill up memory
and evoke garbage collection and run the finalization members of the garbage
Things until #20 is finalized at which time the program exits.
The reason for the funny switch is to demonstrate the two system calls:
System.gc() and System.runFinalization(). The code evokes runFinalization()
by itself on the 4th and 12th pass through the loop. It evokes gc()
by itself on the 8th pass through the loop.
And, it runs gc() followed by runFinalization() after the 16th pass.
Try it and examine the output. As a clue, the garbage collector identifies
all unreferenced objects and marks them available for finalization; finalization
takes the objects marked by the garbage collector, runs their finalization
procedure and frees them memory.
Next time:
I will get to components I promise