Java:终结器
目录
背景返回目录
多数情况我们不需要重写 finalize 方法,只有当我们需要持有未托管资源的时候才需要,而此时重写 finalize 方法,只是作为一个“安全网”,不能作为常规的资源释放模式,必须提供显式的释放方法,如:close。
如果某个类型重写了 finalize 方法,但是这个类型是可以继承的,这就要求所有的子类如果也重写了 finalize,就必须要调用父类的 finalize 方法,我们有三种策略:
- 按照约定。
- 终结器防卫者。
- 模板方法模式。
本文就介绍第 2 种模式,此模式是昨天看《Effective Java 第二版》时学习的,本文后面会介绍 C# 是如何做的。
Java版:终结器防卫者返回目录
测试代码
注意看注释,我就不多说了。

1 public class Program {
2
3 public static void main(String[] args) throws InterruptedException {
4 {
5 new CustomResourceOwner().doSomeThing();
6 }
7
8 System.gc();
9
10 System.out.println("程序结束!");
11 }
12 }
13
14 class ResourceOwnerBase {
15 // 可以将父类中 finalize 的代码放到守卫者里,一定会被调用的。
16 @SuppressWarnings("unused")
17 private final Object finalizeGuarder = new Object() {
18 @Override
19 public void finalize() {
20 System.out.println("在资源守卫者中销毁父类!");
21 }
22 };
23
24 // 子类可能故意不调用父类!
25 @Override
26 public void finalize() {
27 System.out.println("销毁父类!");
28 }
29 }
30
31 final class CustomResourceOwner extends ResourceOwnerBase {
32 @Override
33 public void finalize() {
34 System.out.println("销毁子类!");
35
36 // 故意不调用父类!
37 // super.finalize();
38 }
39
40 public void doSomeThing() {
41 System.out.println("随便做点工作!");
42 }
43 }

输出结果
1 随便做点工作!
2 程序结束!
3 在资源守卫者中销毁父类!
4 销毁子类!
说明
因为终结器防卫者只被资源拥有者持有,当资源拥有者变为垃圾的时候,终结器防卫者也会变为垃圾。
C#版:“终结器防卫者”返回目录
测试代码

1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6 using System.IO;
7
8 namespace DisposeStudy
9 {
10 class Program
11 {
12 static void Main()
13 {
14 {
15 var res = new CustomResourceOwner(IntPtr.Zero);
16 res.DoSomeThing();
17 }
18 }
19 }
20
21 class ResourceOwnerBase : IDisposable
22 {
23 private bool _disposed;
24 private readonly FileStream _fileStream;
25 private IntPtr _handle;
26
27 protected ResourceOwnerBase(IntPtr handle)
28 {
29 _handle = handle;
30 _fileStream = File.OpenRead(@"E:\Coding\HappyStudy\DisposeStudy\DisposeStudy\Program.cs");
31 }
32
33 protected bool Disposed
34 {
35 get { return _disposed; }
36 }
37
38 public void Dispose()
39 {
40 Dispose(true);
41
42 GC.SuppressFinalize(this);
43 }
44
45 protected virtual void Dispose(bool disposing)
46 {
47 if (Disposed)
48 {
49 if (disposing)
50 {
51 _fileStream.Dispose();
52 }
53
54 CloseHandle(_handle);
55 _handle = IntPtr.Zero;
56
57 _disposed = true;
58 }
59 }
60
61 ~ResourceOwnerBase()
62 {
63 Console.WriteLine("父类析构方法!");
64 Dispose(false);
65 }
66
67 [System.Runtime.InteropServices.DllImport("Kernel32")]
68 private extern static Boolean CloseHandle(IntPtr handle);
69 }
70
71 sealed class CustomResourceOwner : ResourceOwnerBase
72 {
73 public CustomResourceOwner(IntPtr handle)
74 : base(handle)
75 {
76 }
77
78 public void DoSomeThing()
79 {
80 if (Disposed)
81 {
82 throw new ObjectDisposedException("资源已经消耗了,不能执行此操作!");
83 }
84
85 Console.WriteLine("随便做点工作!");
86 }
87
88 ~CustomResourceOwner()
89 {
90 Console.WriteLine("子类析构方法!");
91 }
92 }
93 }

输出结果

说明
让我们看看编译器帮我们做了什么工作:

看完大家就明白了,C#在编译器层面保证了子类的终结器一定会调用父类的终结器。
备注返回目录
同时学习 C# 和 Java 是一件挺快乐的事情。
Java:终结器防卫者
Java:终结器的更多相关文章
- Java:终结器防卫者,顺便看一下 C# 如何做的。
背景 多数情况我们不需要重写 finalize 方法,只有当我们需要持有未托管资源的时候才需要,而此时重写 finalize 方法,只是作为一个“安全网”,不能作为常规的资源释放模式,必须提供显式的释 ...
- JVM强引用、软引用、弱引用、虚引用、终结器引用垃圾回收行为总结
JVM引用 我们希望能描述这样一类对象: 当内存空间还足够时,则能保留在内存中:如果内存空间在进行垃圾收集后还是很紧张,则可以抛弃这些对象. -[既偏门又非常高频的面试题]强引用.软引用.弱引用.虚引 ...
- java笔记--理解java类加载器以及ClassLoader类
类加载器概述: java类的加载是由虚拟机来完成的,虚拟机把描述类的Class文件加载到内存,并对数据进行校验,解析和初始化,最终形成能被java虚拟机直接使用的java类型,这就是虚拟机的类加载机制 ...
- java安全管理器SecurityManager入门
table { margin-left: 30px; width: 95%; border: 1px; border-collapse: collapse } img { border: 1px so ...
- java类加载器深入研究
看了下面几篇关于类的加载器的文章,豁然开朗.猛击下面的地址开始看吧. Java类加载原理解析 深入探讨 Java 类加载器 分析BootstrapClassLoader/ExtClassLo ...
- effective java —— 终结方法守卫者
目录: effective java —— 终结方法守卫者 effective java 第2章:创建和销毁对象.第7条 : 避免使用终结方法.最后的“终结方法守卫者 (finalizer guard ...
- 深入探讨 Java 类加载器
转自:http://www.ibm.com/developerworks/cn/java/j-lo-classloader/ 类加载器(class loader)是 Java™中的一个很重要的概念.类 ...
- 高性能Java解析器实现过程详解
如果你没有指定数据或语言标准的或开源的Java解析器, 可能经常要用Java实现你自己的数据或语言解析器.或者,可能有很多解析器可选,但是要么太慢,要么太耗内存,或者没有你需要的特定功能.或者开源解析 ...
- JAVA 类加载器 第14节
JAVA 类加载器 第14节 今天我们将类加载机制5个阶段中的第一个阶段,加载,又叫做装载.为了阅读好区分,以下都叫做装载. 装载的第一步就是要获得二进制的字节流,它可以从读.class文件获得,也可 ...
随机推荐
- Struts2流程
Struts2流程 1.client浏览器初始化时发出HTTP请求 2.依据web.xml配置,上述请求被FilterDispatcher接收 3.依据struts.xml配置,找到须要调用的Acti ...
- shell 命名管道,进程间通信
命名管道基础 命名管道也被称为FIFO文件, 在文件系统中是可见的,并且跟其它文件一样可以读写! 命名管道特点: 当写进程向管道中写数据的时候,如果没有进程读取这些数据,写进程会堵塞 当读取管道中的数 ...
- java_maven_linux_windows下项目运行jar
我才用的是eclipse自带的export功能,暂时没把maven的打包插件研究清楚 导出jar包后,需要用解压缩打开,把配置文件copy到压缩包的内的顶级目录 保存 写 bat 脚本 @author ...
- 【云图】如何制作全国KTV查询系统?
原文:[云图]如何制作全国KTV查询系统? 摘要:本文以[唱吧]531麦霸音乐节为案例,详细解读了如何导入自有数据到高德云图,并进行检索和展示.最后,调起高德mobile地图来进行路线规划和周边查询. ...
- 心有多宽 路就有多宽-- BreezeMH源码公布
非常多话想说,但不知道从何说起~ 去年暑假做自己的第一个外挂,然后是Breeze‘s魔兽系列工具,測试版.正式版,看着自己进大学时的梦想慢慢的变成现实,那种喜悦感无法言表,于是就想着让很多其它的在校大 ...
- 安裝 Rails 開發環境
安裝 Rails 開發環境 Give someone a program, you frustrate them for a day; teach them how to program, you f ...
- HDU 5068 Harry And Math Teacher
主题链接~~> 做题情绪:的非常高深,有种高大上的感觉. 解题思路: 两层之间的联通能够看成是一个矩阵 代表上下两层都能够联通,,代表下层第1个门与上层第一个门不联通,以此类推联通就能够用矩阵 ...
- 记录近期小改Apriori至MapReduce上的心得
·背景 前一阵,一直在研究一些ML的东东,后来工作关系暂停了一阵.现在继续把剩下一些热门的算法再吃吃透,"无聊+逗比"地把他们搞到MapReduce上.这次选择的入手对象为Apri ...
- 在windows下用C语言写socket通讯实例
原文:在windows下用C语言写socket通讯实例 From:Microsoft Dev Center #undef UNICODE #define WIN32_LEAN_AND_MEAN #in ...
- 我的时间,GTD做主
可能每一次总结的时候,我们都在努力的回顾,我这几天都干了什么,结果回顾半天得到的结果就是:我也不知道,仿佛什么都没有做似的.事实上不然,你已经做了好多事,但却始终有这样的感觉,有的时候都在自己发问:我 ...