💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
### [继承和清理](https://lingcoder.gitee.io/onjava8/#/book/09-Polymorphism?id=%e7%bb%a7%e6%89%bf%e5%92%8c%e6%b8%85%e7%90%86) 在使用组合和继承创建新类时,大部分时候你无需关心清理。子对象通常会留给垃圾收集器处理。如果你存在清理问题,那么必须用心地为新类创建一个`dispose()`方法(这里用的是我选择的名称,你可以使用更好的名称)。由于继承,如果有其他特殊的清理工作的话,就必须在派生类中重写`dispose()`方法。当重写`dispose()`方法时,记得调用基类的`dispose()`方法,否则基类的清理工作不会发生: ~~~ // polymorphism/Frog.java // Cleanup and inheritance // {java polymorphism.Frog} package polymorphism; class Characteristic { private String s; Characteristic(String s) { this.s = s; System.out.println("Creating Characteristic " + s); } protected void dispose() { System.out.println("disposing 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("disposing 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()"); } @Override 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()"); } @Override protected void dispose() { System.out.println("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() { System.out.println("Frog()"); } @Override 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(); } } ~~~ 输出: ~~~ Creating Characteristic is alive Creating Description Basic Living Creature LivingCreature() Creating Characteristiv 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 wanter 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 ~~~ 层级结构中的每个类都有**Characteristic**和**Description**两个类型的成员对象,它们必须得被销毁。销毁的顺序应该与初始化的顺序相反,以防一个对象依赖另一个对象。对于属性来说,就意味着与声明的顺序相反(因为属性是按照声明顺序初始化的)。对于基类(遵循 C++ 析构函数的形式),首先进行派生类的清理工作,然后才是基类的清理。这是因为派生类的清理可能调用基类的一些方法,所以基类组件这时得存活,不能过早地被销毁。输出显示了,**Frog**对象的所有部分都是按照创建的逆序销毁的。 尽管通常不必进行清理工作,但万一需要时,就得谨慎小心地执行。 **Frog**对象拥有自己的成员对象,它创建了这些成员对象,并且知道它们能存活多久,所以它知道何时调用`dispose()`方法。然而,一旦某个成员对象被其它一个或多个对象共享时,问题就变得复杂了,不能只是简单地调用`dispose()`。这里,也许就必须使用*引用计数*来跟踪仍然访问着共享对象的对象数量,如下: ~~~ // polymorphism/ReferenceCounting.java // Cleaning up shared member objects class Shared { private int refcount = 0; private static long counter = 0; private final long id = counter++; Shared() { System.out.println("Creating " + this); } public void addRef() { refcount++; } protected void dispose() { if (--refcount == 0) { System.out.println("Disposing " + this); } } @Override public String toString() { return "Shared " + id; } } class Composing { private Shared shared; private static long counter = 0; private final long id = counter++; Composing(Shared shared) { System.out.println("Creating " + this); this.shared = shared; this.shared.addRef(); } protected void dispose() { System.out.println("disposing " + this); shared.dispose(); } @Override 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(); } } } ~~~ 输出: ~~~ 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 ~~~ **static long counter**跟踪所创建的**Shared**实例数量,还提供了**id**的值。**counter**的类型是**long**而不是**int**,以防溢出(这只是个良好实践,对于本书的所有示例,**counter**不会溢出)。**id**是**final**的,因为它的值在初始化时确定后不应该变化。 在将一个**shared**对象附着在类上时,必须记住调用`addRef()`,而`dispose()`方法会跟踪引用数,以确定在何时真正地执行清理工作。使用这种技巧需要加倍细心,但是如果正在共享需要被清理的对象,就没有太多选择了。