|
|
|
|
Inheritance and cleanup
When using composition and inheritance to create a new class, most of the time you won’t have to worry about cleaning up; subobjects can usually be left to the garbage collector. If you do have cleanup issues, you must be diligent and create a dispose( ) method (the name I have chosen to use here; you may come up with something better) for your new class. And with inheritance, you must override dispose( ) in the derived class if you have any special cleanup that must happen as part of garbage collection. When you override dispose( ) in an inherited class, it’s important to remember to call the base-class version of dispose( ), since otherwise the base-class cleanup will not happen. The following example demonstrates this:
//: c07:Frog.java
// Cleanup and inheritance.
import com.bruceeckel.simpletest.*;
class Characteristic {
private String s;
Characteristic(String s) {
this.s = s;
System.out.println("Creating Characteristic " + s);
}
protected void dispose() {
System.out.println("finalizing Characteristic " + s);
}
}
class Description {
private String s;
Description(String s) {
this.s = s;
System.out.println("Creating Description " + s);
}
protected void dispose() {
System.out.println("finalizing Description " + s);
}
}
class LivingCreature {
private Characteristic p = new Characteristic("is alive");
private Description t =
new Description("Basic Living Creature");
LivingCreature() {
System.out.println("LivingCreature()");
}
protected void dispose() {
System.out.println("LivingCreature dispose");
t.dispose();
p.dispose();
}
}
class Animal extends LivingCreature {
private Characteristic p= new Characteristic("has heart");
private Description t =
new Description("Animal not Vegetable");
Animal() {
System.out.println("Animal()");
}
protected void dispose() {
System.out.println("Animal dispose");
t.dispose();
p.dispose();
super.dispose();
}
}
class Amphibian extends Animal {
private Characteristic p =
new Characteristic("can live in water");
private Description t =
new Description("Both water and land");
Amphibian() {
System.out.println("Amphibian()");
}
protected void dispose() {
System.out.println("Amphibian dispose");
t.dispose();
p.dispose();
super.dispose();
}
}
public class Frog extends Amphibian {
private static Test monitor = new Test();
private Characteristic p = new Characteristic("Croaks");
private Description t = new Description("Eats Bugs");
public Frog() {
System.out.println("Frog()");
}
protected void dispose() {
System.out.println("Frog dispose");
t.dispose();
p.dispose();
super.dispose();
}
public static void main(String[] args) {
Frog frog = new Frog();
System.out.println("Bye!");
frog.dispose();
monitor.expect(new String[] {
"Creating Characteristic is alive",
"Creating Description Basic Living Creature",
"LivingCreature()",
"Creating Characteristic has heart",
"Creating Description Animal not Vegetable",
"Animal()",
"Creating Characteristic can live in water",
"Creating Description Both water and land",
"Amphibian()",
"Creating Characteristic Croaks",
"Creating Description Eats Bugs",
"Frog()",
"Bye!",
"Frog dispose",
"finalizing Description Eats Bugs",
"finalizing Characteristic Croaks",
"Amphibian dispose",
"finalizing Description Both water and land",
"finalizing Characteristic can live in water",
"Animal dispose",
"finalizing Description Animal not Vegetable",
"finalizing Characteristic has heart",
"LivingCreature dispose",
"finalizing Description Basic Living Creature",
"finalizing Characteristic is alive"
});
}
} ///:~
Each class in the hierarchy also contains a member objects of types Characteristic and Description, which must also be disposed. The order of disposal should be the reverse of the order of initialization, in case one subobject is dependent on another. For fields, this means the reverse of the order of declaration (since fields are initialized in declaration order). For base classes (following the form that’s used in C++ for destructors), you should perform the derived-class cleanup first, then the base-class cleanup. That’s because the derived-class cleanup could call some methods in the base class that require the base-class components to be alive, so you must not destroy them prematurely. From the output you can see that all parts of the Frog object are disposed in reverse order of creation.
From this example, you can see that although you don’t always need to perform cleanup, when you do, the process requires care and awareness.
|
|
|