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文件获得,也可 ...
随机推荐
- Spring学习使用标签来标记资源(@Component、@Repository、 @Service和@Controller)和用法(包括如何jsp正在使用)
首先,在xml其中新增部分标有下划线的文件,容器初始化的时候需要扫描包 注意: a. 包款扫描(下划线部分)一定要加,默认是不扫描整个包.与每一包之间','开.如过具有同样的父包,那么我们能够 ...
- nginx基础入门
nginx常常被用来处理静态资源如css.js.图片.html等,也被用作反向代理server.邮件server,也时常拿来做负载均衡.它的优势主要体如今对静态资源的处理上,这次抽出了点时间整理了一些 ...
- jQuery插件编写及链式编程模型
jQuery插件编写及链式编程模型小结 JQuery极大的提高了我们编写JavaScript的效率,让我们可以愉快的编写代码,做出各种特效.大多数情况下,我们都是使用别人开发的JQuery插件,今天我 ...
- asp.net 发邮件
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...
- 基于tomcat为了应对高并发模型实现webserver
在博客上,一个简单的AIOweb来样加工.查看AIO异步处理,依靠操作系统完成IO操作Proactor处理模型确实很强大,它可以实现高并发.高响应server一个很好的选择,但在tomcat中间con ...
- vs.net 2013 Saffolding功能扩展
vs.net 2013 Saffolding功能扩展 Asp.net mvc 5 CRUD代码自动生成工具 -Visual Studio.net2013 Saffolding功能扩展 上次做过一个&l ...
- 微软不也是从Altair Basic这丑小鸭长成白天鹅吗?
微软不也是从Altair Basic这丑小鸭长成白天鹅吗? February 2015 如果你想要弄清楚初创企业是怎么一回事的话,其中一个非常有价值的尝试是去研究下那些获得巨大成功的公司,去分析下为什 ...
- oracle获取字符串长度函数length()和hengthb()
原文:oracle获取字符串长度函数length()和hengthb() lengthb(string)计算string所占的字节长度:返回字符串的长度,单位是字节 length(string)计算s ...
- c#开发之多国语言解决方案gnu.gettext + poedit
1.工具简介 1.1.关于i18n i18n其来源是英文单词 internationalization的首末字符i和n,18为中间的字符数是“国际化”的简称. i10n为资源本地化,全称为Locali ...
- 非接触式电子音乐控制器CHIMAERA
本篇文章,我将介绍个有意思的设备. 她就是Chimaera,一个基于电磁场效应的非接触式电子音乐控制器. <弹奏Chimaera的声音> 霍尔效应传感器阵列及其周围部件组成了一个连续的2D ...