`
zhang.jianjun
  • 浏览: 19489 次
  • 性别: Icon_minigender_1
  • 来自: 青岛
最近访客 更多访客>>
社区版块
存档分类
最新评论
  • NGG: 个人建议: 正确的做法应该是把样式放到外部css文件中,使用 ...
    js日期选择器

【JAVA优化编程】内存管理之——(3)Java中的析构方法finalize

阅读更多

3  Java中的析构方法finalize

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

 

    由于GC调用finalize的时间是不确定的,有时我们需要通过其他的手段来释放程序中所占用的系统资源,比如自己在类中声明一个destroy()方法,在这个方法中添加释放系统资源的处理代码,当你使用完该对象后可以通过调用这个destroy()方法来释放该对象内部成员占用的系统资源。并且最好在类的finalize 方法中添加资源释放代码,这样做更为保险、安全。在类深度继承的情况下,这种方法显得就更为有效,我们可以通过递归调用destroy的方法在子类被销毁的时候释放父类所占用的资源,例如下面的代码:

 

    原始基类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();
        super.finalize(); // 递归调用超类中的finalize方法
    }
}

 

 

    一级子类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();
        super.finalize(); // 递归调用超类中的finalize方法
    }
}
 

 

    二级子类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();
        super.finalize(); // 递归调用超类中的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 {

    Object 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。由此可见我们在设计类时尽可能地避免在类的默认构造器中创建、初始化大量的对象,防止在调用其自类的构造器时造成不必要的内存资源浪费,因为即使我们没有想调用父类的构造器创建大量无用的对象(至少有时候这些对象对我们是没有意义的),但是系统都会自动创建它们,而这些操作与过程对于我们来说是隐含的。

0
0
分享到:
评论

相关推荐

    Java中finalize()的用法

    配方详细介绍了在Java中finalize()的用法。

    Java中finalize方法使用.doc

    Java中finalize方法使用

    Java中finalize方法.pdf

    Java中finalize方法.pdf 学习资料 复习资料 教学资源

    详解Java编程中final,finalize,finally的区别

    主要介绍了详解Java编程中final,finalize,finally的区别,这个在Java面试题中简直是太常见了...需要的朋友可以参考下

    Java禁止使用finalize方法共2页.pdf.zip

    Java禁止使用finalize方法共2页.pdf.zip

    java 编程入门思考

    13.16.3 用Java 1.1 AWT制作窗口和程序片 13.16.4 再探早期示例 13.16.5 动态绑定事件 13.16.6 将商业逻辑与UI逻辑区分开 13.16.7 推荐编码方法 13.17 Java 1.1 UI API 13.17.1 桌面颜色 13.17.2 打印 13.17.3 剪贴...

    Java中final,finally,finalize三个关键字的区别_动力节点Java学院整理

    Java中final,finally,finalize三个关键字的区别_动力节点Java学院整理

    java编程常见面试题目

    第一,谈谈final, finally, finalize的区别。   第二,Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)?  第三,Static ...

    JAVA面试题解惑系列合集

    1.4 JAVA面试题解惑系列(四)——final、finally和finalize的区别 1.5 JAVA面试题解惑系列(五)——传了值还是传了引用? 1.6 JAVA面试题解惑系列(六)——字符串(String)杂谈 1.7 JAVA面试题解惑系列(七)...

    Thinking in Java 中文第四版+习题答案

    13.16.3 用Java 1.1 AWT制作窗口和程序片 13.16.4 再探早期示例 13.16.5 动态绑定事件 13.16.6 将商业逻辑与UI逻辑区分开 13.16.7 推荐编码方法 13.17.1 桌面颜色 13.17.2 打印 13.17.3 剪贴板 13.18 可视编程和 ...

    Java中针对finalize的实现和相应的执行过程

     这个引用对象专门为带finalize方法的类服务,可以理解为每一个有相应的方法的对象,其都会封装为一种finalRefernece对象.  因为finalize方法是object定义的,其默认实现为空.那么如果重写了此方法,那么方法体...

    《剑指offer》Java深入理解final、finally、finalize.pdf

    final 是 Java 中的关键字,它也是 Java 中很重要的一个关键字,final 修饰的类、方法、变量有不同的含义;finally 也是一个关键字,不过我们可以使用 finally 和其他关键字结合做一些组合操作; finalize 是一个不...

    张孝祥Java培训教程

    3,finalize()方法是在对象被当成垃圾从内存中释放前调用,而不是在对象变成垃圾前调用。 4,main只在类被装载时调用,因此只会执行一次。在类的实例里main函数并不会被执行。 5,类的static属性在类被装载时被...

    Java禁止使用finalize方法

    主要介绍了Java禁止使用finalize方法,需要的朋友可以参考下

    Java面试大全(备战2021) 最新Java面试必问合集 PDF版

    Java面试大全是一套最新Java面试必问合集,这本面试手册包含了Java基础、Java集合、JVM、Spring、Spring Boot、Spring Cloud、Mysql、Redis、RabbitMQ、Dubbo、Netty、分布式及架构设计等方面的技术点。内容难度参差...

    opencvmem:OpenCV Java内存管理

    Java 9中不推荐使用Object.finalize方法,因此,依赖此方法肯定会在将来破坏OpenCVJava绑定。 使用它的论点是没有意义的。 阅读我为OpenCV开发人员进行更正的。先决条件仅当您希望自己进行实验时,才需要这样做。 ...

    Java中覆盖finalize()方法实例代码

    主要介绍了Java中覆盖finalize()方法实例代码,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下

    Thinking in java4(中文高清版)-java的'圣经'

    2.8.2 语法 2.8.3 嵌入式HTML 2.8.4 一些标签示例 2.8.5 文档示例 2.9 编码风格 2.10 总结 2.11 练习 第3章 操作符 3.1 更简单的打印语句 3.2 使用Java操作符 3.3 优先级 3.4 赋值 3.4.1 方法调用中的别名问题 3.5 ...

    Java中finalize()详解及用法

    主要介绍了Java中finalize()详解及用法的相关资料,final是Java的关键字,它所表示的是“这部分是无法修改的”,需要的朋友可以参考下

    JAVA面试题最全集

    方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() ...

Global site tag (gtag.js) - Google Analytics