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) ...
随机推荐
- Morris Traversal方法遍历
实现二叉树的遍历且只需要O(1)的空间. 参考:http://www.cnblogs.com/AnnieKim/archive/2013/06/15/MorrisTraversal.html
- Java显式锁学习总结之五:ReentrantReadWriteLock源码分析
概述 我们在介绍AbstractQueuedSynchronizer的时候介绍过,AQS支持独占式同步状态获取/释放.共享式同步状态获取/释放两种模式,对应的典型应用分别是ReentrantLock和 ...
- cvc-complex-type.2.4.a: Invalid content was found starting with element ‘init-param’(转)
在写xml的时候又一次总是报cvc-complex-type.2.4.a: Invalid content was found starting with element 错误,还出现小红叉,在网上找 ...
- hdu 3573(数学+贪心)
Buy Sticks Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- jmeter-----用户参数和用户定义变量的区别
在调试脚本的时候,可以使用前置处理器中的用户参数组件进行数据的提供,在该数据中可以使用固定值也可以使用变量值. 如果是固定不变的一些配置项,不需要多个值的时候,也可以使用用户已定义的变量组件. 一.界 ...
- 简单的oracle sql语句练习
简单的oracle sql语句练习 求每个部门的平均薪水 select deptno,avg(sal) from emp group by deptno 每个部门同一个职位的最大工资 select d ...
- 井字棋游戏升级版 - TopTicTacToe项目 简介
一.游戏简介 井字棋是一款世界闻名的游戏,不用我说,你一定知道它的游戏规则. 这款游戏简单易学,玩起来很有意思,不过已经证明出这款游戏如果两个玩家都足够聪明的话, 是很容易无法分出胜负的,即我们得到的 ...
- 湖南大学ACM程序设计新生杯大赛(同步赛)B - Build
题目描述 In country A, some roads are to be built to connect the cities.However, due to limited funds, ...
- 深度学习应用系列(四)| 使用 TFLite Android构建自己的图像识别App
深度学习要想落地实践,一个少不了的路径即是朝着智能终端.嵌入式设备等方向发展.但终端设备没有GPU服务器那样的强大性能,那如何使得终端设备应用上深度学习呢? 所幸谷歌已经推出了TFMobile,去年又 ...
- 【SQL】175. Combine Two Tables
Table: Person +-------------+---------+ | Column Name | Type | +-------------+---------+ | PersonId ...