转自:http://www.cnblogs.com/isline/archive/2010/08/31/1813396.html

Sealed与Final修饰符其实并不是一个语言平台的产物,他们有着各自所属的语言环境,但这两个关键字都是.Net平台中不可或缺的,那么二者用法几何,随本文一探究竟。

一.Sealed

sealed 修饰符可以应用于类、实例方法和属性。用于类时,该类被称为密封类,密封类不能被继承;用于方法时,该方法被称为密封方法,密封方法会重写基类中的方法;sealed修饰符应用于方法或属性时,必须始终与override一起使用;结构是隐式密封的,因此它们不能被继承。

● 描述方法:

//Error: cannot be sealed because it is not an override
    public sealed string func()
    {
      return "";
    }

//OK

public sealed override string func()
    {
      return "";
    }

● 继承中的方法:(TestChild2中无法重写任何方法)

●描述属性:

public sealed override double Hours
    {
       get { return 0.1; }
       set { }
    }

●描述变量:

//Error The modifier 'sealed' is not valid for this item
    sealed override string a;

●描述接口:

interface Itesta
    {
      //Error cannot be sealed because it is not an override
      sealed string Geta();
    }

● sealed能提高性能优化?

有一些朋友认为当元素被标记为sealed时,有助于系统运行性能的提升,其理由有2:

1有助于JIT内联。

2消除了协变与逆变和后期绑定,使CLR直接执行这个实例。

这看似是有些道理的,可这样做又会提升多少性能,提升性能的同时又损失了什么呢?

先说说“第1点”,促使JIT内联代码的因素有很多,JIT不会因为一个类是sealed,就去装入其中的内容(详见.Net Discovery 系列之六--深入浅出.Net实时编译机制(下),这也不符合程序局部性原理。http://www.cnblogs.com/isline/archive/2009/12/27/1633453.html),而对于sealed类内部方法的内联,很大原因也是由于方法槽映射关系决定的,sealed作用有待考证。

第2点,由于sealed类不可派生或被继承,所以的确在运行时省去可CLR一些额外的工作,但是这些工作只是一些类似于“寻址”的工作,因为虚拟方法表已经完成了运行时与编译时的对应关系,纯粹的运行时只是在寻找这些关系而已,所以sealed省去的只是一部分较为复杂的寻址关系,因为即使没有继承,也不可避免一个方法表的应用。

而这样做又损失了什么呢?大家想想,面向对象的原因是什么?是提升性能吗?显然不是,面向对象的只是高级语言层面的,最终运行的代码都是以顺序流程的方式出现,面向对象的本质是“抽象”,它解决的是软件产品的“控制”问题,变不可控为可控,变不可预测的风险为可预测的风险,所以如果因为要提升性能,而把大部分类都sealed化,岂不是大大削弱了面向对象的抽象能力呢?

● Sealed不能同时abstract?

也许在高级语言中抽象须实现与密封不可继承是一对矛盾者,但IL暴露了一些不一样的细节,让我们来分析一下这段IL代码:

这段代码简单得很,就是声明了一个类,然而这个类却是abstract和Sealed的,猜猜这个类用了什么修饰符修饰它?

好吧,其实高级语言中对应的修饰符就是static。

static类不能被实例化(abstract)亦不可派生(Sealed),我想abstract同时Sealed也未尝不可,但这样做会使语义出现二义性,为避免这种效果才规定在编辑器中不可abstract+Sealed,static修饰类的初衷我想也是如此,实际上static在修饰类时,就是一个包含了实现的abstract+Sealed的类,这个类不能被实例化也不能派生出新的类。

二.Final

final修饰符来限定变量、字段、方法和类。用于变量时,该变量只能赋值一次,不可修改;用于方法时,该方法不能被重写或隐藏;用于类时,该类不能被继承。

接口的成员是不能使用该关键字的,道理和不能在abstract类使用final一样。

值得一提的是,如果使用final修饰类中的字段,那么该字段必须在构造函数中赋值,否则使用类实例调用的方式是无法对该字段进行赋值的,道理很简单,类在实例化时,会为每一个成员字段赋初值,之后你如果再通过实例方式调用该final字段,就属于二次赋值的情况了,这种情况是不允许的。在构造函数中为final变量赋值的方法叫做“延时赋值”(Java),相应的final变量叫做“空白final”(Java)。

Final并不是一个C#中的关键字,但经常在C#面试题中出现,例如说说“Final、Finally、finalize的区别”,其实这已经超出C#的范畴,这三个关键字分别考核了J#、.Net 容错方法、.Net垃圾收集机制,奇怪的是,每次我面试C#程序人员时,大部分人员对Final这个关键字并无陌生之感,相反却答得头头是道,看来来面试之前,早在网上有所预习,呵呵。

例子(摘自MSDN,已做翻译):

public class Value

{

public int i = 1;

}

public class FinalData

{

//可认为等同于编译时常量

final int i1 = 9;

static final int i2 = 99;

//public 常量:

public static final int i3 = 999;

//不可作为编译时常量:

final int i4 = (int)(Math.random() * 11);

static final int i5 = (int)(Math.random() * 11);

Value v1 = new Value();

final Value v2 = new Value();

static final Value v3 = new Value();

// 数组:

final int[] a = { 1, 2, 3, 4, 5, 6 };

public void print(String id)

{

System.out.println(id + ": " + "i4 = " + i4 + ", i5 = " + i5);

}

public static void main(String[] args)

{

FinalData fd1 = new FinalData();

// Error: Can't change value! (i1被描述为fianl的)

// fd1.i1++;

// OK. Object isn't constant(虽然v2是fianl的,但其中的变量并不受此约束)

fd1.v2.i++;

// OK. Not final.

fd1.v1 = new Value();

for (int i = 0; i < fd1.a.length; i++)

{

fd1.a[i]++; // OK. Object isn't constant.(与上面那个v2一样,数组是final的,但数组元素不受约束)

}

// Error: Can't change handle! (v2是final的)

// fd1.v2 = new Value();

// Error: Can't change handle! (v3是static final的,等同于常量)

// fd1.v3 = new Value();

// Error: Can't change handle!(数组本身是final,不可new)

// fd1.a = new int[3];

fd1.print("fd1");

System.out.println("Creating new FinalData");

FinalData fd2 = new FinalData();

fd1.print("fd1");

fd2.print("fd2");

}

}

答案:

-------------------------------------------------河蟹的分割线-------------------------------------------------------

fd1: i4 = 0, i5 = 7

Creating new FinalData

fd1: i4 = 0, i5 = 7

fd2: i4 = 8, i5 = 7

总结:final是J#中的一种修饰符,在VS2008及以后版本中就放弃J#了,它与sealed不同的是fianl可以修饰变量,而sealed则不能,不过你可以通过readonly关键字来实现。

关于二者对性能的提升作用,我认为有待考证,从理论层面来讲,为难以证明的性能因素而特意使用此关键字有些得不偿失。

天道酬勤不酬怨 
李鸣(aicken)原创 转载注明

漫谈.Net关键字系列之一Sealed与Final(转)的更多相关文章

  1. 漫谈程序员系列:3D打印能打印出程序员吗

    首先声明,本文是一本正经的胡扯,绝不是随随便便的胡扯,请您不要随便攻击我胡说八道.我要反复星爷在<喜剧之王>里的台词:事实上.我是一本正经的喷子. 3D打印的定义 关于3D打印,以下是来自 ...

  2. 漫谈程序猿系列:无BUG不生活

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZm9ydW9r/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/d ...

  3. C#sealed和final

    sealed用于类时,该类被称为密封类,密封类不能被继承: C#提出了密封方法(sealed method) 的概念,以防止在方法所在类的派生类中对该方法的重载.对方法可以使用sealed 修饰符,这 ...

  4. java关键字native、static、final详解

    native: native关键字说明其修饰的方法是一个原生态方法,方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中.Java语言本身不能对操作系统底层进行访问和操作,但是可 ...

  5. 打字练习-编程语言关键字系列-java

    小编整理的java关键字,内容如下:abstract, assert, boolean, break, byte, case, catch, char, class, const, continue, ...

  6. 浅谈Dynamic 关键字系列之一:dynamic 就是Object(转)

    C# 4.0提供了一个dynamic 关键字,那么什么是dynamic,究竟dynamic是如何工作的呢? 从最简单的示例开始: static void Main(string[] args) { d ...

  7. 射频识别技术漫谈(11)——Mifare系列卡的共性【worldsing笔记】

    Mifare是NXP公司生产的一系列遵守ISO14443A标准的射频卡,包Mifare S50.Mifare S70.Mifare UltraLight.Mifare Pro.Mifare Desfi ...

  8. 漫谈程序猿系列:她发现了一个Bug……

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZm9ydW9r/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/d ...

  9. 射频识别技术漫谈(22)——RC系列射频芯片的寄存器操作

    前面提到,RC系列内部64个寄存器的正确操作是软件编写的关键.正确设置寄存器首先要做到与寄存器正确通信,其次是要对寄存器写入正确的值. RC系列射频芯片与微控制器的接口有并口和SPI接口两种类型.显然 ...

随机推荐

  1. Spring Boot干货系列:(一)优雅的入门篇

    Spring Boot干货系列:(一)优雅的入门篇 2017-02-26 嘟嘟MD 嘟爷java超神学堂   前言 Spring一直是很火的一个开源框架,在过去的一段时间里,Spring Boot在社 ...

  2. 手动挡C1驾驶学车@长建驾校

    2015-11-01 下午取钱去长建驾校报名学车 4600(学费) + 100(暂住证) + 30(照片) + 10(体检) 2015-11-14 8:00-12:00 理论课2 光盘10  2015 ...

  3. display与visibility的区别

    style.visibility和style.display都可以实现对页的隐藏,但visibility要占用域的空间,而display则不占用 将元素display属性设为 block,会在该元素后 ...

  4. tomcat 启动自动加载外部项目

    conf/server.xml 配置 <!--<Context path="/upload" docBase="E://upload" />- ...

  5. 用Python写一个猜数字游戏

    2015.5.25第一天下载Python IDLE,写个猜数字的小游戏来熟悉这门语言: times=6 letters=[100] for i in range(1,times): a = input ...

  6. 1326: The contest(并查集+分组背包)

    http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1326 殷犇有很多队员.他们都认为自己是最强的,于是,一场比赛开始了~ 于是安叔主办了一场比赛,比赛 ...

  7. 基于jQuery悬停弹出遮罩显示按钮代码

    今天给大家分享一款基于jQuery悬停弹出遮罩显示按钮代码.这是是一款当鼠标悬停在图片上后,会出现一系列的按钮,文字等弹性动画效果.效果图如下: 在线预览   源码下载 实现的代码. html代码: ...

  8. css让footer永远保持在页面底部

    案例1:仅仅保存在页面底部.不固定. 思路: html: <div class="body"> <header>我是头部</header> &l ...

  9. 嘿, 你知道吗, 再也不需要for循环了!

    做一个优雅的程序员 JavaScript是一门优雅的语言, 这个'优雅'体验在JS逻辑层次处于高段位的水平, 什么意思呢, 就是一个js应用的主线剧情一定全部是函数式表达的高层可读逻辑, 还是不懂? ...

  10. java- Servlet-session

    Servlet 相关:http://blog.csdn.net/ggGavin/article/category/2134213 Servlet——Session(1)之基础知识 Servlet——S ...