为什么我们需要密封类?

穆罕默德·比拉尔·雷尔曼

我知道Sealed类的功能。那是不可继承的。但是我的问题是为什么我们需要密封班?如果动机不是继承属性和方法,为什么不仅仅将它们声明为私有?

伊凡·波塔(Ivan Porta)

首先,让我们从定义开始。密封是修饰符,如果应用于类将使其不可继承,并且应用于虚拟方法或属性将使其不可识别。

public sealed class A { ... }
public class B 
{
    ...
    public sealed string Property { get; set; }
    public sealed void Method() { ... }
}

其用法的一个示例是定义专门的类/方法或属性,在其中可能发生的更改可能会使它们停止按预期方式工作(例如,System.Drawing命名空间的Pens类)。

...
namespace System.Drawing
{
    //
    // Summary:
    //     Pens for all the standard colors. This class cannot be inherited.
    public sealed class Pens
    {
        public static Pen Transparent { get; }
        public static Pen Orchid { get; }
        public static Pen OrangeRed { get; }
        ...
    }
}

因为密封的类不能被继承,所以它不能用作基类,因此抽象类不能使用密封的修饰符。

同样重要的是要提到结构是隐式密封的。

性能

要真正看到它们,您需要分析JIT编译的编码(最后一个)。

C#代码

public sealed class Sealed
{
    public string Message { get; set; }
    public void DoStuff() { }
}
public class Derived : Base
{
    public sealed override void DoStuff() { }
}
public class Base
{
    public string Message { get; set; }
    public virtual void DoStuff() { }
}
static void Main()
{
    Sealed sealedClass = new Sealed();
    sealedClass.DoStuff();
    Derived derivedClass = new Derived();
    derivedClass.DoStuff();
    Base BaseClass = new Base();
    BaseClass.DoStuff();
}

MIL代码

.method private hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       41 (0x29)
  .maxstack  8
  IL_0000:  newobj     instance void ConsoleApp1.Program/Sealed::.ctor()
  IL_0005:  callvirt   instance void ConsoleApp1.Program/Sealed::DoStuff()
  IL_000a:  newobj     instance void ConsoleApp1.Program/Derived::.ctor()
  IL_000f:  callvirt   instance void ConsoleApp1.Program/Base::DoStuff()
  IL_0014:  newobj     instance void ConsoleApp1.Program/Base::.ctor()
  IL_0019:  callvirt   instance void ConsoleApp1.Program/Base::DoStuff()
  IL_0028:  ret
} // end of method Program::Main

JIT编译代码

--- C:\Users\Ivan Porta\source\repos\ConsoleApp1\Program.cs --------------------
        {
0066084A  in          al,dx  
0066084B  push        edi  
0066084C  push        esi  
0066084D  push        ebx  
0066084E  sub         esp,4Ch  
00660851  lea         edi,[ebp-58h]  
00660854  mov         ecx,13h  
00660859  xor         eax,eax  
0066085B  rep stos    dword ptr es:[edi]  
0066085D  cmp         dword ptr ds:[5842F0h],0  
00660864  je          0066086B  
00660866  call        744CFAD0  
0066086B  xor         edx,edx  
0066086D  mov         dword ptr [ebp-3Ch],edx  
00660870  xor         edx,edx  
00660872  mov         dword ptr [ebp-48h],edx  
00660875  xor         edx,edx  
00660877  mov         dword ptr [ebp-44h],edx  
0066087A  xor         edx,edx  
0066087C  mov         dword ptr [ebp-40h],edx  
0066087F  nop  
            Sealed sealedClass = new Sealed();
00660880  mov         ecx,584E1Ch  
00660885  call        005730F4  
0066088A  mov         dword ptr [ebp-4Ch],eax  
0066088D  mov         ecx,dword ptr [ebp-4Ch]  
00660890  call        00660468  
00660895  mov         eax,dword ptr [ebp-4Ch]  
00660898  mov         dword ptr [ebp-3Ch],eax  
            sealedClass.DoStuff();
0066089B  mov         ecx,dword ptr [ebp-3Ch]  
0066089E  cmp         dword ptr [ecx],ecx  
006608A0  call        00660460  
006608A5  nop  
            Derived derivedClass = new Derived();
006608A6  mov         ecx,584F3Ch  
006608AB  call        005730F4  
006608B0  mov         dword ptr [ebp-50h],eax  
006608B3  mov         ecx,dword ptr [ebp-50h]  
006608B6  call        006604A8  
006608BB  mov         eax,dword ptr [ebp-50h]  
006608BE  mov         dword ptr [ebp-40h],eax  
            derivedClass.DoStuff();
006608C1  mov         ecx,dword ptr [ebp-40h]  
006608C4  mov         eax,dword ptr [ecx]  
006608C6  mov         eax,dword ptr [eax+28h]  
006608C9  call        dword ptr [eax+10h]  
006608CC  nop  
            Base BaseClass = new Base();
006608CD  mov         ecx,584EC0h  
006608D2  call        005730F4  
006608D7  mov         dword ptr [ebp-54h],eax  
006608DA  mov         ecx,dword ptr [ebp-54h]  
006608DD  call        00660490  
006608E2  mov         eax,dword ptr [ebp-54h]  
006608E5  mov         dword ptr [ebp-44h],eax  
            BaseClass.DoStuff();
006608E8  mov         ecx,dword ptr [ebp-44h]  
006608EB  mov         eax,dword ptr [ecx]  
006608ED  mov         eax,dword ptr [eax+28h]  
006608F0  call        dword ptr [eax+10h]  
006608F3  nop  
        }
0066091A  nop  
0066091B  lea         esp,[ebp-0Ch]  
0066091E  pop         ebx  
0066091F  pop         esi  
00660920  pop         edi  
00660921  pop         ebp  

00660922  ret  

尽管对象的创建是相同的,但是执行执行以调用密封和派生/基类的方法的指令略有不同。将数据移入寄存器或RAM(移动指令)后,调用密封方法,在dword ptr [ecx],ecx(cmp指令)之间执行比较,然后在派生/基类直接执行该方法的同时调用该方法。 。

根据Torbjorn Granlund撰写的报告,AMD和Intel x86处理器的指令等待时间和吞吐量, Intel Pentium 4中以下指令的速度为:

  • mov:具有1个周期的等待时间,并且这种类型的处理器每个周期可以支持2.5条指令
  • cmp:具有1个周期的等待时间,处理器每个此类周期可维持2条指令

链接https : //gmplib.org/~tege/x86-timing.pdf

编译器的优化使密封和未密封分类的性能之间的差异变得如此之小,以至于我们谈论的是处理器界,因此对于大多数应用程序而言,它们是无关紧要的。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Java

为什么我们需要Java中的Properties类?

来自分类Dev

为什么我们需要需求?

来自分类Dev

我们为什么需要`ngDoCheck`

来自分类Linux

为什么我们需要mktemp?

来自分类Dev

为什么我们需要单子?

来自分类Dev

我们为什么需要ʻiteratoreltype()`?

来自分类Dev

我们为什么需要容器?

来自分类Dev

为什么我们需要cmake?

来自分类Dev

为什么我们需要IO?

来自分类Dev

为什么我们需要主键?

来自分类Java

为什么我们需要将Object类作为所有类的基类?

来自分类Dev

如果包装器类已经不可变,为什么我们需要Atomic *类?

来自分类Dev

为什么我们既需要未来又需要承诺?

来自分类Dev

为什么我们需要分开Apply和Applicative类型类?

来自分类Dev

Android:扩展应用程序类。为什么我们需要实现单例模式?

来自分类Dev

为什么我们需要在类路径后写“ *”

来自分类Java

为什么说我们不需要克隆一个不可变类?

来自分类Java

为什么我们需要在<persistence-unit>元素内指定类?

来自分类Java

为什么我们需要Java中的用户定义的类加载器

来自分类Dev

为什么我们需要特定的类来处理请求和响应?

来自分类Linux

为什么我们需要__init__来初始化python类

来自分类Dev

为什么我们可以对类本身进行操作,但又需要接口呢?

来自分类Dev

为什么我们在python中的每个方法上都需要相应的类函数?

来自分类Dev

为什么我们需要在 Spring Data JPA 中使用 @Transactional 注释 Service 类

来自分类Dev

为什么不同于类的其他成员,我们为什么需要定义类的静态变量?

来自分类Dev

什么是 TLS,我们为什么需要它?

来自分类Dev

什么是稀疏文件,为什么我们需要它?

来自分类Dev

什么是BIOS,为什么我们需要它?

来自分类Java

什么是对象发布,为什么我们需要它?

Related 相关文章

  1. 1

    为什么我们需要Java中的Properties类?

  2. 2

    为什么我们需要需求?

  3. 3

    我们为什么需要`ngDoCheck`

  4. 4

    为什么我们需要mktemp?

  5. 5

    为什么我们需要单子?

  6. 6

    我们为什么需要ʻiteratoreltype()`?

  7. 7

    我们为什么需要容器?

  8. 8

    为什么我们需要cmake?

  9. 9

    为什么我们需要IO?

  10. 10

    为什么我们需要主键?

  11. 11

    为什么我们需要将Object类作为所有类的基类?

  12. 12

    如果包装器类已经不可变,为什么我们需要Atomic *类?

  13. 13

    为什么我们既需要未来又需要承诺?

  14. 14

    为什么我们需要分开Apply和Applicative类型类?

  15. 15

    Android:扩展应用程序类。为什么我们需要实现单例模式?

  16. 16

    为什么我们需要在类路径后写“ *”

  17. 17

    为什么说我们不需要克隆一个不可变类?

  18. 18

    为什么我们需要在<persistence-unit>元素内指定类?

  19. 19

    为什么我们需要Java中的用户定义的类加载器

  20. 20

    为什么我们需要特定的类来处理请求和响应?

  21. 21

    为什么我们需要__init__来初始化python类

  22. 22

    为什么我们可以对类本身进行操作,但又需要接口呢?

  23. 23

    为什么我们在python中的每个方法上都需要相应的类函数?

  24. 24

    为什么我们需要在 Spring Data JPA 中使用 @Transactional 注释 Service 类

  25. 25

    为什么不同于类的其他成员,我们为什么需要定义类的静态变量?

  26. 26

    什么是 TLS,我们为什么需要它?

  27. 27

    什么是稀疏文件,为什么我们需要它?

  28. 28

    什么是BIOS,为什么我们需要它?

  29. 29

    什么是对象发布,为什么我们需要它?

热门标签

归档