Java中包含继承关系时对象的创建与销毁顺序详解(附源码)

前言

通过组合和继承方法来创建新类时,永远不必担心对象的清理问题,子对象通常都会留给垃圾回收器进行处理。如果确实遇到清理的问题,那么必须用心为新类创建dispose()方法(在这里我选用此名称,读者可以提出更好的)。并且由于继承的缘故,如果我们有其他作为垃圾回收一部分的特殊清理动作,就必须在导出类中覆盖dispose()方法。当覆盖被继承类的dispose()方法时,务必记住调用基类版本dispose()方法;否则,基类的清理动作就不会发生。下例就证明了这一点:

示例源码

package com.mufeng.theeighthchapter;

class Characteristic {// 特征
	private String s;

	public Characteristic(String s) {
		// TODO Auto-generated constructor stub
		this.s = s;
		System.out.println("Creating Characteristic " + s);
	}

	protected void dispose() {
		System.out.println("disposing Characteristic " + s);
	}
}

class Description {// 描述
	private String s;

	public Description(String s) {
		// TODO Auto-generated constructor stub
		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");

	public LivingCreature() {
		// TODO Auto-generated constructor stub
		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");

	public Animal() {
		// TODO Auto-generated constructor stub
		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");

	public Amphibian() {
		// TODO Auto-generated constructor stub
		System.out.println("Amphibian()");
	}

	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() {
		// TODO Auto-generated constructor stub
		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();
	}

}

输出结果

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

源码解析

层次结构中的每个类都包含CharacteristicDescription这两种类型的成员对象,并且它们也必须被销毁。所以万一某个子对象要依赖于其他对象,销毁的顺序应该和初始化顺序相反。对于字段,则意味着与声明的顺序相反(因为字段的初始化是按声明的顺序进行的)。对于基类(遵循C++中析构函数的形式),应该首先对于其导出类进行清理,然后才是基类。这是因为导出类的清理可能会调用基类中的某些方法,所以需要使基类中的构件仍起作用而不应该过早地销毁它们。从输出结果可以看到,Frog对象的所有部分都是按照创建的逆序进行销毁的。

在这个例子中可以看到,尽管通常不必执行清理工作,但是一旦选择要执行,就必须谨慎和小心。

时间: 2024-11-05 17:18:51

Java中包含继承关系时对象的创建与销毁顺序详解(附源码)的相关文章

java中的继承关系

1.定义 java中的继承是单一的,一个子类只能拥有一个父类:java中所有类的父类是java.lang.Object,除了这个类之外,每个类只能有一个父类: 而一个父类可以有多个子类,可以被多个子类继承: Java只支持单继承,也就是说,一个类不能继承多个类. Java只支持单继承(继承基本类和抽象类),但是我们可以用接口来实现(多继承{实现}接口来实现),脚本结构如: public class One extends Parent implements Two,Three,Four{} 2.

Java中的继承关系的加载顺序

/* 在加载类时,Java虚拟机先加载父类再加载子类,再对静态初始化块. 静态成员变量(类变量).静态方法进行一次初始化. 只有调用new方法时才会创建类的对象.按照父子继承关系进行初始化, 首先执行父类的初始化块部分,然后是父类的构造方法,再执行子类的 初始化块,最后是子类的构造方法. 销毁对象的过程是:首先销毁子类部分,再销毁父类部分. */ public class InheritanceLoadOrder { public static void main(String[] args)

Java 中break和continue结合标签标示符中断循环示例详解(附源码)

臭名昭著的goto 编程语言中一开始就有goto关键词了.事实上,goto起源于汇编语言的程序控制:"若条件A成立,则跳到这里:否则跳到那里".如果阅读由编译器最终生成的汇编代码,就会发现程序控制里包含了许多跳转.(Java编译器生成它自己的"汇编代码",但是这个代码是运行在Java虚拟机上的,而不是直接运行在CPU硬件上.) goto语句是在源码级上的跳转,这使其招致了不好的声誉.若一个程序总是从一个地方跳到另一个地方,还有什么办法能识别程序的控制流程呢?自从Ed

Cocos2dx-3.x 中CCCamera相机类详解及源码分析

Cocos2d-x 3.3版本中加入了相机这个类,该类在3D游戏中是必不可少的,在3D立体游戏中,往往需要视野角度的变化,通过相机的变换才能观察和体验整个游戏世界. CCCamera类基本使用 在游戏中一般有两种类型的相机:一种是透视相机,它在3D游戏中十分常见:另一种是正交相机,它没有透视相机的近大远小的效果而是相机内任何位置的物体大小比例都是一样的. 上图是透视相机的原理图,一般来说,我们通过以下代码创建: _camera = Camera::createPerspective(60, (G

Servlet容器Tomcat中web.xml中url-pattern的配置详解[附带源码分析]

前言 今天研究了一下tomcat上web.xml配置文件中url-pattern的问题. 这个问题其实毕业前就困扰着我,当时忙于找工作. 找到工作之后一直忙,也就没时间顾虑这个问题了. 说到底还是自己懒了,没花时间来研究. 今天看了tomcat的部分源码 了解了这个url-pattern的机制.  下面让我一一道来. tomcat的大致结构就不说了, 毕竟自己也不是特别熟悉. 有兴趣的同学请自行查看相关资料. 等有时间了我会来补充这部分的知识的. 想要了解url-pattern的大致配置必须了解

详解Redis源码中的部分快速排序算法(pqsort.c)

看标题,你可能会疑惑:咦?你这家伙,怎么不讲解完整的快排,只讲一部分快排---.- 哎,冤枉."部分快排"是算法的名字,实际上本文相当详细呢.本文几乎与普通快排无异.看懂了本文,你对普通的快排也会有更深的认识了. 快速排序算法(qsort)的原理我们大都应该了解.本文介绍的是部分快速排序算法.其实其算法本质是一样的,只不过限定了排序的左右区间,也就是只对一个数字序列的一部分进行排序,故称为"部分快速排序算法",简称:pqsort Redis项目中的pqsort.c

java中子类继承父类时是否继承构造函数

来源:http://www.cnblogs.com/sunnychuh/archive/2011/09/09/2172131.html --------------------- java继承中对构造函数是不继承的,只是调用(隐式或显式). 以下是例子: public class FatherClass { public FatherClass() {       System.out.println(100); } public FatherClass(int age) {      Syst

Java中的继承与静态static等的执行先后顺序

package extend; public class X { Y y=new Y(); static{  System.out.println("tttt"); } X(){  System.out.println("X"); }  public static void main(String[] args) {    new Z(); }} class Y{ Y(){  System.out.println("Y"); }} class Z

Tomcat中session详解(源码阅读)

Tomcat中的session是通过一个manager来管理的,其中Session接口默认实现类有StandardSession,管理器的默认实现是StandardManager. 我们平时在servlet中使用的session也就是HashMap中的一个session对象,同时session除了在内存存储,同时还提供了持久化方法,tomcat中持久化有两种,一种是保存为文件,另一种则是保存到数据库. 这一节首先来看一下默认的StandardSession和StandardManager. pu