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关键字来实现。

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

-------------------------------------------------------------------------------------------------------------------

注:本文转载于:http://www.cnblogs.com/isline/archive/2010/08/31/1813396.html,感谢原文作者!

C#中的Sealed和J#中的Final比较(转载)的更多相关文章

  1. C# 中的sealed修饰符学习

    转载原地址 http://developer.51cto.com/art/200908/147327.htm C#语言还是比较常见的东西,这里我们主要介绍C# sealed修饰符,包括介绍两个修饰符在 ...

  2. j中的substr(start,length)和substring(start,stop)

    j中的substr(start,length)和substring(start,end) substring 1 substring 方法用于提取字符串中介于两个指定下标之间的字符(包头不包尾) 2 ...

  3. SpringMVC 实现POI读取Excle文件中数据导入数据库(上传)、导出数据库中数据到Excle文件中(下载)

    读取Excale表返回一个集合: package com.shiliu.game.utils; import java.io.File; import java.io.FileInputStream; ...

  4. 一个字符串中可能包含a~z中的多个字符,如有重复,如String data="aavzcadfdsfsdhshgWasdfasdf",求出现次数最多的那个字母及次数,如有多个重复的则都求出。

    主要掌握String中的方法 char[] toCharArray()           将此字符串转换为一个新的字符数组. int indexOf(String str)           返回 ...

  5. 重新想象 Windows 8 Store Apps (24) - 文件系统: Application Data 中的文件操作, Package 中的文件操作, 可移动存储中的文件操作

    原文:重新想象 Windows 8 Store Apps (24) - 文件系统: Application Data 中的文件操作, Package 中的文件操作, 可移动存储中的文件操作 [源码下载 ...

  6. Oracle sql 中的字符(串)替换与转换[转载]

    1.REPLACE 语法:REPLACE(char, search_string,replacement_string) 用法:将char中的字符串search_string全部转换为字符串repla ...

  7. 已知一个字符串S 以及长度为n的字符数组a,编写一个函数,统计a中每个字符在字符串中的出现次数

    import java.util.Scanner; /** * @author:(LiberHome) * @date:Created in 2019/3/6 21:04 * @description ...

  8. C#提取PPT文本——提取SmartArt中的文本、批注中的文本

    提取文本的情况在工作和学习中常会遇到,在前面的文章中,已经讲述了如何提取PPT中文本框里的文本,在本篇文章中,将介绍如何使用C#代码语言提取PPT文档中SmartArt和批注中的文本.同样的,程序里面 ...

  9. [多问几个为什么]为什么匿名内部类中引用的局部变量和参数需要final而成员字段不用?(转)

    昨天有一个比较爱思考的同事和我提起一个问题:为什么匿名内部类使用的局部变量和参数需要final修饰,而外部类的成员变量则不用?对这个问题我一直作为默认的语法了,木有仔细想过为什么(在分析完后有点印象在 ...

随机推荐

  1. 为什么一定要学Go语言

    Go语言是谷歌2009发布的第二款开源编程语言.Go语言专门针对多处理器系统应用程序的编程进行了优化,使用Go编译的程序可以媲美C或C++代码的速度,而且更加安全.支持并行进程. 为什么要选择学习Go ...

  2. 简易APB4 slave实践

    一个简易的(不完整的)APB4 slave的可以没有PREADY和PSLVERR,这两个信号都被赋予常数,以及没有PPROT. 两种不同类型的寄存器: 图: 普通寄存器电路图 图: 带读写控制寄存器电 ...

  3. 微信内置浏览器H5 弹出键盘 遮盖文本框解决办法 Fixed失效

    if(/Android [4-6]/.test(navigator.appVersion)) { window.addEventListener("resize", functio ...

  4. 3.nginx日志

    1. 自定义日志格式为json log_format json '{"@timestamp":"$time_iso8601",' '"@version ...

  5. python设计模式--读书笔记

    GoF在其设计模式一书中提出了23种设计模式,并将其分为三类: 创建型模式 将对象创建的细节隔离开来,代码与所创建的对象的类型无关. 结构型模式 简化结构,识别类与对象间的关系,重点关注类的继承和组合 ...

  6. JMeterPlugins插件

    一.线程组1.jp@gc - Stepping Thread Group,如下图: 类似loadrunner的场景设置,解释:This Group will start 10 threads:这次的测 ...

  7. (转)基于CentOS 7安装Zabbix 3.4和Zabbix4.0

    原文:https://blog.csdn.net/leshami/article/details/78708049 CentOS 7环境下Zabbix4.0的安装和配置实例-----------htt ...

  8. 单元测试工具 - karma

    在离开上一家公司之前,team leader 在我离开前留给了我最后几个关键字:karma,断言库,JASMINE,QUNIT,MOCHA. 可一直拖拖沓沓的,没有去了解.直到今天,才终于抽出心情和时 ...

  9. online contest

    http://atcoder.jp/contest https://nanti.jisuanke.com/contest http://codeforces.com/ https://www.nowc ...

  10. AngularJS的基础知识

    一.AngularJS指令与表达式 [AngularJS常用指令]1.ng-app:声明Angular所管辖的区域,一般写在body或HTML上,原则上一个页面只有一个.2.ng-model:把元素值 ...