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 是一件挺快乐的事情。

  • 相关阅读:
    团队活动
    实力提升
    软工人必须要知道的几个工具
    博客/论坛:(技术分享)
    CSS怎样设置多个字体,设置多个字体的时候要注意什么
    canvas绘制bitmap全部填充(当bitmap的宽高小于绘制区域的时候)
    CSS字体
    weditor元素定位异常
    python ImportError: C extension: DLL load failed while importing strptim
    python:导入不同路径下相同名称的模块
  • 原文地址:https://www.cnblogs.com/happyframework/p/3358456.html
Copyright © 2011-2022 走看看