Java:终结器防卫者,顺便看一下 C# 如何做的。
背景
多数情况我们不需要重写 finalize 方法,只有当我们需要持有未托管资源的时候才需要,而此时重写 finalize 方法,只是作为一个“安全网”,不能作为常规的资源释放模式,必须提供显式的释放方法,如:close。
如果某个类型重写了 finalize 方法,但是这个类型是可以继承的,这就要求所有的子类如果也重写了 finalize,就必须要调用父类的 finalize 方法,我们有三种策略:
- 按照约定。
- 终结器防卫者。
- 模板方法模式。
本文就介绍第 2 种模式,此模式是昨天看《Effective Java 第二版》时学习的,本文后面会介绍 C# 是如何做的。
Java版:终结器防卫者
测试代码
注意看注释,我就不多说了。
public class Program {
public static void main(String[] args) throws InterruptedException {
{
new CustomResourceOwner().doSomeThing();
}
System.gc();
System.out.println("程序结束!");
}
}
class ResourceOwnerBase {
// 可以将父类中 finalize 的代码放到守卫者里,一定会被调用的。
@SuppressWarnings("unused")
private final Object finalizeGuarder = new Object() {
@Override
public void finalize() {
System.out.println("在资源守卫者中销毁父类!");
}
};
// 子类可能故意不调用父类!
@Override
public void finalize() {
System.out.println("销毁父类!");
}
}
final class CustomResourceOwner extends ResourceOwnerBase {
@Override
public void finalize() {
System.out.println("销毁子类!");
// 故意不调用父类!
// super.finalize();
}
public void doSomeThing() {
System.out.println("随便做点工作!");
}
}
输出结果
随便做点工作!
程序结束!
在资源守卫者中销毁父类!
销毁子类!
说明
因为终结器防卫者只被资源拥有者持有,当资源拥有者变为垃圾的时候,终结器防卫者也会变为垃圾。
C#版:“终结器防卫者”
测试代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO; namespace DisposeStudy
{
class Program
{
static void Main()
{
{
var res = new CustomResourceOwner(IntPtr.Zero);
res.DoSomeThing();
}
}
} class ResourceOwnerBase : IDisposable
{
private bool _disposed;
private readonly FileStream _fileStream;
private IntPtr _handle; protected ResourceOwnerBase(IntPtr handle)
{
_handle = handle;
_fileStream = File.OpenRead(@"E:\Coding\HappyStudy\DisposeStudy\DisposeStudy\Program.cs");
} protected bool Disposed
{
get { return _disposed; }
} public void Dispose()
{
Dispose(true); GC.SuppressFinalize(this);
} protected virtual void Dispose(bool disposing)
{
if (Disposed)
{
if (disposing)
{
_fileStream.Dispose();
} CloseHandle(_handle);
_handle = IntPtr.Zero; _disposed = true;
}
} ~ResourceOwnerBase()
{
Console.WriteLine("父类析构方法!");
Dispose(false);
} [System.Runtime.InteropServices.DllImport("Kernel32")]
private extern static Boolean CloseHandle(IntPtr handle);
} sealed class CustomResourceOwner : ResourceOwnerBase
{
public CustomResourceOwner(IntPtr handle)
: base(handle)
{
} public void DoSomeThing()
{
if (Disposed)
{
throw new ObjectDisposedException("资源已经消耗了,不能执行此操作!");
} Console.WriteLine("随便做点工作!");
} ~CustomResourceOwner()
{
Console.WriteLine("子类析构方法!");
}
}
}
输出结果

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

看完大家就明白了,C#在编译器层面保证了子类的终结器一定会调用父类的终结器。
备注
同时学习 C# 和 Java 是一件挺快乐的事情。
Java:终结器防卫者,顺便看一下 C# 如何做的。的更多相关文章
- Java:终结器
目录 背景Java版:终结器防卫者C#版:“终结器防卫者”备注 背景返回目录 多数情况我们不需要重写 finalize 方法,只有当我们需要持有未托管资源的时候才需要,而此时重写 finalize 方 ...
- Java类加载器( 死磕 4)
[正文]Java类加载器( CLassLoader ) 死磕 之4: 神秘的双亲委托机制 本小节目录 4.1. 每个类加载器都有一个parent父加载器 4.2. 类加载器之间的层次关系 4.3. ...
- JVM强引用、软引用、弱引用、虚引用、终结器引用垃圾回收行为总结
JVM引用 我们希望能描述这样一类对象: 当内存空间还足够时,则能保留在内存中:如果内存空间在进行垃圾收集后还是很紧张,则可以抛弃这些对象. -[既偏门又非常高频的面试题]强引用.软引用.弱引用.虚引 ...
- 深入理解Java类加载器(二):线程上下文类加载器
摘要: 博文<深入理解Java类加载器(一):Java类加载原理解析>提到的类加载器的双亲委派模型并不是一个强制性的约束模型,而是Java设计者推荐给开发者的类加载器的实现方式.在Java ...
- java类加载器深入研究
看了下面几篇关于类的加载器的文章,豁然开朗.猛击下面的地址开始看吧. Java类加载原理解析 深入探讨 Java 类加载器 分析BootstrapClassLoader/ExtClassLo ...
- 深入探讨 Java 类加载器
转自:http://www.ibm.com/developerworks/cn/java/j-lo-classloader/ 类加载器(class loader)是 Java™中的一个很重要的概念.类 ...
- 高性能Java解析器实现过程详解
如果你没有指定数据或语言标准的或开源的Java解析器, 可能经常要用Java实现你自己的数据或语言解析器.或者,可能有很多解析器可选,但是要么太慢,要么太耗内存,或者没有你需要的特定功能.或者开源解析 ...
- 深入探讨 Java 类加载器[转]
原文地址:http://www.ibm.com/developerworks/cn/java/j-lo-classloader/index.html 类加载器(class loader)是 Java™ ...
- 转载:深入探讨 Java 类加载器
转载地址 : http://www.ibm.com/developerworks/cn/java/j-lo-classloader/ 深入探讨 Java 类加载器 类加载器(class loader) ...
随机推荐
- 洛谷 P2639 [USACO09OCT]Bessie的体重问题Bessie's We… 题解
题目传送门 这也是个01背包,只是装的很... #include<bits/stdc++.h> #define MAXN 45010 using namespace std; int f[ ...
- 【BZOJ】4311: 向量(线段树分治板子题)
题解 我们可以根据点积的定义,垂直于原点到给定点构成的直线作一条直线,从正无穷往下平移,第一个碰到的点就是答案 像什么,上凸壳哇 可是--动态维护上凸壳? 我们可以离线,计算每个点能造成贡献的一个询问 ...
- 三 Python解释器
当我们编写Python代码时,我们得到的是一个包含Python代码的以.py为扩展名的文本文件.要运行代码,就需要Python解释器去执行.py文件. 由于整个Python语言从规范到解释器都是开源的 ...
- 解决引入keras后出现的Using TensorFlow backend的错误
在引入头文件之后,加入 import os os.environ['KERAS_BACKEND']='tensorflow' 就可以完美解决这个问题
- Python画一朵花
from mpl_toolkits.mplot3d import Axes3D from matplotlib import cm from matplotlib.ticker import Line ...
- java短信接口调用
java短信接口调用 之前一直在一个传统的单位上班好多听容易的技术都没接触过,即使有时候想搞一搞类似于支付宝支付,短信接口调用,微信公众号,小程序之类等功能,一直有心无力终于跳槽了,估计是氛围的原因吧 ...
- java基础小测试
1.JDK,JRE,JVM三者的区别 jdk:java 开发工具包 jre:运行环境 jvm:虚拟机 2.javac的作用 ,反编译工具的作用 javac:将java文件编译成class文件 反编译: ...
- vim自动补全插件YouCompleteMe的安装及配置
原文地址: http://blog.csdn.net/shixuehancheng/article/details/46289811
- FastReport.Net使用:[17]线(Line)控件使用
FastReport中,线(Line)控件怎么用?怎么画一条美观的线? 认识Line控件 1.线(Line)控件包含于形状(Shape)控件中,有5个可选项,一个标准线和四个对角线,其实都是同一种线, ...
- 【BZOJ 4229】 4229: 选择 (线段树+树链剖分)
4229: 选择 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 67 Solved: 41 Description 现在,我想知道自己是否还有选择. ...