Java:终结器防卫者,顺便看一下 C# 如何做的。

java

多数情况我们不需要重写 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:\Coding\HappyStudy\DisposeStudy\DisposeStudy\Program.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 是一件挺快乐的事情。

以上是 Java:终结器防卫者,顺便看一下 C# 如何做的。 的全部内容, 来源链接: utcz.com/z/391543.html

回到顶部