zoukankan      html  css  js  c++  java
  • Java:终结器防卫者,顺便看一下 C# 如何做的。

    背景

    多数情况我们不需要重写 finalize 方法,只有当我们需要持有未托管资源的时候才需要,而此时重写 finalize 方法,只是作为一个“安全网”,不能作为常规的资源释放模式,必须提供显式的释放方法,如:close。

    如果某个类型重写了 finalize 方法,但是这个类型是可以继承的,这就要求所有的子类如果也重写了 finalize,就必须要调用父类的 finalize 方法,我们有三种策略:

    1. 按照约定。
    2. 终结器防卫者。
    3. 模板方法模式。

    本文就介绍第 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:CodingHappyStudyDisposeStudyDisposeStudyProgram.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 是一件挺快乐的事情。

  • 相关阅读:
    【bzoj2280】[Poi2011]Plot 二分+倍增+二分+最小圆覆盖
    【bzoj1336/1337/2823】[Balkan2002]Alien最小圆覆盖 随机增量法
    【bzoj4999】This Problem Is Too Simple! 树链剖分+动态开点线段树
    【bzoj3435】[Wc2014]紫荆花之恋 替罪点分树套SBT
    【bzoj3217】ALOEXT 替罪羊树套Trie树
    【bzoj3065】带插入区间K小值 替罪羊树套权值线段树
    【bzoj4012】[HNOI2015]开店 动态点分治+STL-vector
    【bzoj3924】[Zjoi2015]幻想乡战略游戏 动态点分治
    【bzoj1095】[ZJOI2007]Hide 捉迷藏 动态点分治+堆
    【bzoj3329】Xorequ 数位dp+矩阵乘法
  • 原文地址:https://www.cnblogs.com/happyframework/p/3358456.html
Copyright © 2011-2022 走看看