Java中的析构方法finalize

在C++程序设计中有构造函数与析构函数的概念,并且是内存管理技术中相当重要的一部分,而在Java语言中只有构造器(也可以称为构造函数)的概念,却没有析构器或析构函数的概念。这是因为,理论上JVM负责对象的析构(销毁与回收)工作。也就是上面讲到的垃圾回收的概念。那么Java语言中是否真的不存在与C++中析构函数职能类似的方法?其实Java语言中的finalize 方法与C++语言中的析构函数的职能就极为类似。finalize方法是Java语言根基类Object类中所包含的一个方法,这个方法是保护类型的方法(protected),由于在Java应用中开发的所有类都为Object的子类,因此用户类都从Object对象中隐式地继承了该方法。因此,我们在Java类中可以调用其父类的finalize方法,并且可以覆盖自身继承来的finalize方法。虽然我们可以在一个Java类中调用其父类的finalize方法,但是由于finalize方法没有自动实现递归调用,我们必须手动实现,因此finalize函数的最后一个语句通常是super.finalize()语句。通过这种方式,我们可以实现从下到上finalize的迭代调用,即先释放用户类自身的资源,然后再释放父类的资源。通常我们可以在finalize方法中释放一些不容易控制,并且非常重要的资源,例如:一些I/O的操作,数据的连接。这些资源的释放对整个应用程序是非常关键的。

finalize方法最终是由JVM中的垃圾回收器调用的,由于垃圾回收器调用finalize的时间是不确定或者不及时的,调用时机对我们来说是不可控的,因此,有时我们需要通过其他的手段来释放程序中所占用的系统资源,比如自己在类中声明一个destroy()方法,在这个方法中添加释放系统资源的处理代码,当你使用完该对象后可以通过调用这个destroy()方法来释放该对象内部成员占用的系统资源。虽然我们可以通过调用自己定义的destroy()方法释放系统资源,但是还是建议你最好将对destroy()方法的调用放入当前类的finalize()方法体中,因为这样做更保险,更安全。在类深度继承的情况下,这种方法就显得更为有效了,我们可以通过递归调用destroy的方法在子类被销毁的时候释放父类所占用的资源,例如下面的代码:

1.原始基类A

public class A {

Object a = null;

public A() {

a = new Object();

System.out.println("创建a对象");

}

protected void destroy() {

System.out.println("释放a对象");

a = null;

// 释放自身所占用的资源

}

protected void finalize() throws java.lang.Throwable {

destroy();

// 递归调用超类中的finalize方法

super.finalize();

}

}

2.一级子类B

public  class B extends A {

Object b = null;

public B() {

b = new Object();

System.out.println("创建b对象");

}

protected void destroy() {

b = null;

// 释放自身所占用的资源

System.out.println("释放b对象");

super.destroy();

}

protected void finalize() throws java.lang.Throwable {

destroy();

// 递归调用超类中的finalize方法

super.finalize();

}

}

3.二级子类C

public class C extends B {

Object c = null;

public C() {

c = new Object();

System.out.println("创建c对象");

}

protected void destroy() {

c = null;

// 释放自身所占用的资源

System.out.println("释放c对象");

super.destroy();

}

protected void finalize()throws java.lang.Throwable {

destroy();

// 递归调用超类中的finalize方法

super.finalize();

}

}

上面的三个类的继承关系是非常明晰的:A->B->C,类A是原始基类(这是一种习惯叫法),类B继承了类A,类C又继承了类B。其实类A并不是真正意义上的原始基类,上面我们已经提到过Java语言中的原始基类是Object类,尽管我们并没有显式的声明,但这已经是系统约定俗成的了。

为了简单清楚地说明问题,我们在这三个类中分别声明了3个方法,用来论证上面所讲解的知识点,在类A的构造器中我们初始化了一个对象a,在destroy方法中通过a = null;释放其自身所占用的资源。并且在finalize方法中,我们调用了destroy方法用来释放其自身所占用的资源,然后调用其超类Object的finalize方法,这是我们以上所提到的“双保险”的内存释放方法;类B与类C的结构与类A极为相似,它们除了释放自身所占用的资源外,它们还在其对应的方法中调用其超类的destroy方法与finalize方法,用来释放超类所占用的资源。如在类B中调用其超类A的destroy方法与finalize方法与在类C中调用其超类B的destroy方法与finalize方法。但是类A与类B、类C有一点不同,那就是在其destroy方法中没有super.destroy()语句,这是因为其超类Object并没有destroy方法。下面看一下当我们调用初始化与销毁类C时,会有什么样的情况发生。以下是调用完成这个过程的测试类Test的源代码:

public class Test {

c = null;

public Test () {

c = new C();

}

public static void main(String args[]) {

MyClass me = new MyClass();

me.destroy();

}

protected void destroy () {

if (c != null) {

c.destroy();

}else {

System.out.println("c对象已被释放");

}

}

}

编译执行Test.java:

> javac Test.java

> java Test

下面是这个程序的运行结果:

创建a对象

创建b对象

创建c对象

释放c对象

释放b对象

释放a对象

我们注意到当在Test类中初始化类C的对象时,其构造器产生了递归调用,并且是由基类开始依次调用、初始化成员对象的,而当调用C类对象的destroy方法时系统同样产生了递归调用,但调用的顺序却与初始化调用的顺序完全相反,释放资源的调用顺序是由子类开始的,依次调用其超类的资源释放方法destroy()。由此可见,我们在设计类时应尽可能地避免在类的默认构造器中创建、初始化大量的对象。一个原因是在实例化自身的情况下,造成较大的资源开销;另一个原因是其子类在被实例化时,也同样会带来较大的系统资源开销。因为即使我们没有想调用父类的构造器创建大量无用的对象(至少有时候这些对象对我们是没有意义的),但是系统会自动创建它们,而这些操作与过程对于我们来说是隐含的。为了防止上述情况的发生,造成不必要的内存资源浪费,我们应当尽量不在类的构造器中创建、初始化大量的对象或执行某种复杂、耗时的运算逻辑。

转载自http://blog.csdn.net/dongliheng/article/details/1686258

Java中的析构方法finalize相关推荐

  1. java 构造方法和析构方法_PHP面向对象程序设计之构造方法和析构方法详解

    本文实例讲述了PHP面向对象程序设计之构造方法和析构方法.分享给大家供大家参考,具体如下: 构造方法和析构方法是对象中的两个特殊方法,它们都与对象的生命周期有关.构造方法是对象创建完成后第一个被对象自 ...

  2. JAVA中复制数组的方法

     在JAVA里面,可以用复制语句"A=B"给基本类型的数据传递值,但是如果A,B是两个同类型的数组,复制就相当于将一个数组变量的引用传递给另一个数组;如果一个数组发生改变,那么 ...

  3. Java中的main()方法详解

    源文作者:leizhimin    源文链接:http://lavasoft.blog.51cto.com/62575/53263 源文作者版权申明: 版权声明:原创作品,允许转载,转载时请务必以超链 ...

  4. 如何在java中调用js方法

    [java] view plain copy/* * 加载脚本引擎,并在java中调用js方法 */ public void test2() { ScriptEngineManager manager ...

  5. java中构造方法和方法全面解析

    java中构造方法和方法全面解析 我相信大多说人都对构造方法.方法不陌生,而且很了解,但我也相信有很多像我这样的没有一个很好很清晰很全面的认识,今天就把它整理如下,希望能给大家带来点方便与帮助,也希望 ...

  6. java中的dispose()方法

    java中的dispose()方法 先来看看 JAVA 1.5 的帮助文档的原文 - dispose - public void dispose() ****** 释放由此 Window.其子组件及其 ...

  7. java 重写方法 访问权限_为何Java中子类重写方法的访问权限不能低于父类中权限(内含里氏替换原则)...

    为何Java中子类重写方法的访问权限不能低于父类中权限 因为 向上转型及Java程序设计维护的原因 例: 假设一个父类A 拥有的方法public void setXXX(){}可以被其他任意对象调用这 ...

  8. Java中重写equals()方法时注意点

    Java中重写equals()方法时注意点 一直说,重写一个对象的equals()方法时我们必须重写HashCode()方法,但是如果我们不重写呢?会有什么影响呢? 首先看一下,什么情况下我们需要重写 ...

  9. JAVA中list.contains()方法,要重写equals(),hashcode()方法

    今天动力节点java培训机构小编为大家介绍"JAVA中list.contains()方法,要重写equals(),hashcode()方法",希望能够帮助正在学习java的零基础学 ...

最新文章

  1. Python的应用及优缺点分析
  2. 快评 美国软件开发杂志的最新jolt大奖!
  3. ANDROID中ACTIVITY间的数据传递
  4. SQL点滴27—性能分析之执行计划
  5. SDOI2014 旅行
  6. 关于 RGB 的颜色认知
  7. mysql数据库教程全解_MySQL数据库基础教程详解
  8. emmc linux 识别分区_linux下给U盘分区并制作文件系统
  9. 信号通讯编程,王明学learn
  10. Lecture 2:马尔可夫决策
  11. LIO-SAM探秘第三章之代码解析(三) --- mapOptmization.cpp (1)
  12. CC2530_ZigBee+华为云IOT:设计一套属于自己的冷链采集系统
  13. CAJ论文格式转PDF(附带书签)
  14. 华为携西班牙电信于智利设立NB-IoT开放实验室
  15. 专科咋了?5年时间从三流外包到阿里P6,逆袭成功终于肝出了这份大厂Android研发岗中高级面经!
  16. 通过云片网实现短信以及验证码的发送
  17. 关闭烦人的wps广告
  18. jetson 板卡功率测试
  19. 八十八枚红手印背后的故事
  20. C语言--使用指针实现删除字符串中的空格

热门文章

  1. android+动画+锯齿,Android_rotate--animation 动画旋转两图片,消除动画锯齿现象 android 开发:动画旋转两图片 - 下载 - 搜珍网...
  2. android清理缓存功能吗,Android清理缓存功能实现
  3. 软件的极简主义的三个大敌:配置文件,冗余的参数,和大量复杂的接口。
  4. c# 去除字符串中的换行符 \r\n
  5. Git学习笔记与IntelliJ IDEA整合
  6. poj 1252 Euro Efficiency (01背包变形)
  7. 怎么确定迭代器后面还有至少两个值_学会迭代和迭代器,让你的程序更省内存...
  8. Reactor线程模型
  9. ElasticSearch核心基础之索引管理
  10. (66)FPGA面试题-为parallel encoder编写Verilog代码,实现MUX4_1