1、由于Mouse2对象创建了其成员对象rodent2,并且知道它们应该存活多久(只要Mouse2还存活着),因此Mouse2知道何时调用dispose去释放(销毁)成员对象。
以什么顺序去释放?
销毁的顺序应该和初始化顺序相反。这是因为导出类的清理可能会调用基类中的某些方法,所以应该让基类中的构件仍然起作用而不应该过早的消毁。
a)对于字段,则意味着与声明的顺序相反;
b)对于基类,则首先对其导出类进行清理,然后才是基类;
例程:
//: polymorphism/Frog.java
// Cleanup and inheritance.
package polymorphism;
import static net.mindview.util.Print.*;
class Characteristic {
private String s;
Characteristic(String s) {
this.s = s;
print("Creating Characteristic " + s);
}
protected void dispose() {
print("disposing Characteristic " + s);
}
}
class Description {
private String s;
Description(String s) {
this.s = s;
print("Creating Description " + s);
}
protected void dispose() {
print("disposing Description " + s);
}
}
class LivingCreature {
private Characteristic p =
new Characteristic("is alive");
private Description t =
new Description("Basic Living Creature");
LivingCreature() {
print("LivingCreature()");
}
protected void dispose() {
print("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() { print("Animal()"); }
protected void dispose() {
print("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() {
print("Amphibian()");
}
protected void dispose() {
print("Amphibian dispose");
t.dispose();
p.dispose();
super.dispose();
}
}
public class Frog extends Amphibian {
private Characteristic p = new Characteristic("Croaks");
private Description t = new Description("Eats Bugs");
public Frog() { print("Frog()"); }
protected void dispose() {
print("Frog dispose");
t.dispose();
p.dispose();
super.dispose();
}
public static void main(String[] args) {
Frog frog = new Frog();
print("Bye!");
frog.dispose();
}
} /* Output:
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
disposing Description Eats Bugs
disposing Characteristic Croaks
Amphibian dispose
disposing Description Both water and land
disposing Characteristic can live in water
Animal dispose
disposing Description Animal not Vegetable
disposing Characteristic has heart
LivingCreature dispose
disposing Description Basic Living Creature
disposing Characteristic is alive
*///:~
2、同时,当成员对象存在于其他一个或者多个对象共享的情况时,就不能单纯的只是调用dispose()方法去释放成员空间了,必须使用引用计数来跟踪另外还有几个对象在共享该成员对象了。方法是,使用一个变量来计数,本例中使用refcount计数
例程:
//: polymorphism/ReferenceCounting.java
// Cleaning up shared member objects.
import static net.mindview.util.Print.*;
class Shared {
private int refcount = 0;
private static long counter = 0;
private final long id = counter++;
public Shared() {
print("Creating " + this);
}
public void addRef() { refcount++; }
protected void dispose() {
if(--refcount == 0)
print("Disposing " + this);
}
public String toString() { return "Shared " + id; }
}
class Composing {
private Shared shared;
private static long counter = 0;
private final long id = counter++;
public Composing(Shared shared) {
print("Creating " + this);
this.shared = shared;
this.shared.addRef();
}
protected void dispose() {
print("disposing " + this);
shared.dispose();
}
public String toString() { return "Composing " + id; }
}
public class ReferenceCounting {
public static void main(String[] args) {
Shared shared = new Shared();
Composing[] composing = { new Composing(shared),
new Composing(shared), new Composing(shared),
new Composing(shared), new Composing(shared) };
for(Composing c : composing)
c.dispose();
}
} /* Output:
Creating Shared 0
Creating Composing 0
Creating Composing 1
Creating Composing 2
Creating Composing 3
Creating Composing 4
disposing Composing 0
disposing Composing 1
disposing Composing 2
disposing Composing 3
disposing Composing 4
Disposing Shared 0
*///:~
3、1和2两种结合在一起例程,本例中使用share计数:
package polymorphism;
class Member {
public Member(String id) {
System.out.println("Member constructor " + id);
}
public void dispose(){
}
}
class Rodent2 {
private int share = 0;
Member m1 = new Member("m1"), m2 = new Member("m2");
public Rodent2() { System.out.println("Rodent constructor"); }
public void hop() {System.out.println("Rodent hopping"); }
public void scurry() { System.out.println("Rodent scurrying");}
public void reproduce() {System.out.println("Making more Rodents");}
public String toString() { return "Rodent"; }
public void add(){
share++;
System.out.println("Rodent2 was shared "+ share +" times");
}
public void dispose(){
if(--share ==0){
System.out.println("dispose Rodent2!");
}
System.out.println("Rodent2 now "+share+" times");
m2.dispose();//字段按照定义的相反顺序释放;
m1.dispose();
}
/*在虚拟机进行垃圾回收该内存时,检验是否满足这个条件,不满足的话,说明程序有隐藏的漏洞,可以帮助程序员发现这种具有不确定性(不定时发生的)的Bug;
判断条件为何为share>0?
继承(导出类中嵌入基类对象):由于继承关系中在导出类中释放空间时调用super.dispose()会产生share = -1的情况;
组成(通过引用在导出类中使用基类或者其他类的对象):当Rodent为成员变量时,调用dispose()会产生share = 0;
*/
protected void finalize(){
if(share > 0){
System.out.println("Error: 还有引用,不能回收内存!");
}
}
}
class Mouse2 extends Rodent2 {
private static int counter = 0;
private final int id = counter++;
private Rodent2 rodent2 = new Rodent2();
Member m1 = new Member("m1"), m2 = new Member("m2");
public Mouse2() {System.out.println("Mouse constructor");}
public Mouse2(Rodent2 rodent2){
this.rodent2 = rodent2;
rodent2.add();
System.out.println("Mouse constructor");
}
@Override
public void dispose(){
System.out.print("Dispose Mouse2 "+ id +" share ");
rodent2.dispose();//字段按照定义的相反顺序释放;
m2.dispose();
m1.dispose();
super.dispose();//由于继承隐式的嵌入了基类的子对象在导出类中,所以也应该清除,并且应该注意的是:这个嵌入的子对象和本例中引用rodent2指向的对象不同,该子对象的share值为0,当调用super.dispose()后,share值变为-1;
}
@Override
public void hop() {System.out.println("Mouse hopping");}
@Override
public void scurry() {System.out.println("Mouse scurrying");}
@Override
public void reproduce() {System.out.println("Making more Mice");}
@Override
public String toString() { return "Mouse"; }
}
public class E12_RodentInitialization {
public static void main(String args[]) {
Rodent2 r2 = new Rodent2();
Mouse2[] mouse2s = {new Mouse2(r2),new Mouse2(r2),new Mouse2(r2),new Mouse2(r2),new Mouse2(r2)};
for(Mouse2 m2 :mouse2s){
m2.dispose();
}
}
}
/*
Output
Member constructor m1
Member constructor m2
Rodent constructor
Member constructor m1
Member constructor m2
Rodent constructor
Member constructor m1
Member constructor m2
Rodent constructor
Member constructor m1
Member constructor m2
Rodent2 was shared 1 times
Mouse constructor
Member constructor m1
Member constructor m2
Rodent constructor
Member constructor m1
Member constructor m2
Rodent constructor
Member constructor m1
Member constructor m2
Rodent2 was shared 2 times
Mouse constructor
Member constructor m1
Member constructor m2
Rodent constructor
Member constructor m1
Member constructor m2
Rodent constructor
Member constructor m1
Member constructor m2
Rodent2 was shared 3 times
Mouse constructor
Member constructor m1
Member constructor m2
Rodent constructor
Member constructor m1
Member constructor m2
Rodent constructor
Member constructor m1
Member constructor m2
Rodent2 was shared 4 times
Mouse constructor
Member constructor m1
Member constructor m2
Rodent constructor
Member constructor m1
Member constructor m2
Rodent constructor
Member constructor m1
Member constructor m2
Rodent2 was shared 5 times
Mouse constructor
Dispose Mouse2 0 share Rodent2 now 4 times
Rodent2 now -1 times
Dispose Mouse2 1 share Rodent2 now 3 times
Rodent2 now -1 times
Dispose Mouse2 2 share Rodent2 now 2 times
Rodent2 now -1 times
Dispose Mouse2 3 share Rodent2 now 1 times
Rodent2 now -1 times
Dispose Mouse2 4 share dispose Rodent2!
Rodent2 now 0 times
Rodent2 now -1 times
*/