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) ...
随机推荐
- (三)Spring 之AOP 详解
第一节:AOP 简介 AOP 简介:百度百科: 面向切面编程(也叫面向方面编程):Aspect Oriented Programming(AOP),是软件开发中的一个热点,也是Spring框架中的一个 ...
- hdu 5895(矩阵快速幂+欧拉函数)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5895 f(n)=f(n-2)+2*f(n-1) f(n)*f(n-1)=f(n-2)*f(n-1)+2 ...
- Validate Binary Search Tree——体现二查搜索树思想的一道题
Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is defined as ...
- fedora下中文输入fcitx4.0
fedora12,14下使用fcitx输入法可用,切换ctrl+space
- day1 作业编写登录窗口
作业一:编写登录接口 (1)输入用户名和密码: (2)认证成功后显示欢迎信息: (3)输错三次后锁定. 思路:我们知道,要想让程序记住之前输入多少次,锁定用户,那么可以使用数据库来保存用户的状态,然而 ...
- python ConfigParser 配置读写
我们写程序的时候一般都会写程序包的时候,很少硬编码写在一起,这有个很好的配置文件包. 参考 ConfigParser 和 ConfigParser 的使用 一.ConfigParser 简介 C ...
- pyqt5之QColorDialog颜色对话框最简单使用
设置窗体背景颜色 QWidget.setStyleSheet('QWidget {background-color:#88ab45}') 颜色对话框取得颜色值是十六进制. col=QCo ...
- docker-compose RabbitMQ与Nodejs接收端同时运行时的错误
首先讲一下背景: 我现在在开发的一个项目,需要运行RabbitMQ和Nodejs接收端(amqplib库),但是在Nodejs接收端运行时,无法连接至RabbitMQ端,经常提示说 connect E ...
- CentOS使用
centos7编译安装git最新版 CentOS下 pycharm开发环境搭建之无穷无尽的问题 CentOS 7入门操作基础教程 centos中文站 CentOS7 常用命令集合 centos中有vi ...
- Python开发基础-Day33 IO模型
IO模型分类 五种IO Model blocking IO 阻塞IO nonblocking IO 非阻塞IO IO multiplexing IO多路复用 signal driven IO 信号驱动 ...