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. yum安装pip命令

    pip命令是python里的命令,类似于linux系统里的yum命令 我们只需要安装python-pip这个包即可. yum -y install  python-pip 在linux下还有一个命令: ...

  2. CDQZ Day5

    1DP #1题目名称 题目名称匹配块路径染色输入文件名 输入文件名match.in.in.inblock.inpath.inpaint.in输出文件名 输出文件名match.out.out.out.o ...

  3. Struts2和SpringMVC的action是单例还是原型的?

    struts2的acion单独使用的时候应是多例的,也就是原型(prototype). 因为它是基于类开发的,它的三种获取页面传参的方式都是通过成员变量的方式来接受的. 如果用struts2框架基于方 ...

  4. Which mb sdconnect c4 worth the money?

    MB SD connect C4 with laptop v2018.5 Version avaiable now ,It is ready to work after you get it ,wor ...

  5. c#操作mysql

    using System; using MySql.Data; using MySql.Data.MySqlClient; using System.Data; using System.Linq; ...

  6. java se系列(十一)线程

    1 线程的概述 进程:正在运行的程序,负责了这个程序的内存空间分配,代表了内存中的执行区域. 线程:就是在一个进程中负责一个执行路径. 多线程:就是在一个进程中多个执行路径同时执行. 图上的一键优化与 ...

  7. web.py简易示例

    http://webpy.org/cookbook/index.zh-cn code.py import web urls = ( '/', 'index' ) class index: def GE ...

  8. 3dsmax2020卸载/安装失败/如何彻底卸载清除干净3dsmax2020注册表和文件的方法

    3dsmax2020提示安装未完成,某些产品无法安装该怎样解决呢?一些朋友在win7或者win10系统下安装3dsmax2020失败提示3dsmax2020安装未完成,某些产品无法安装,也有时候想重新 ...

  9. jQuery练习 | 提交表单验证

    执行函数时,raturn false可阻止标签(例如超链接)的事件发生,从而达到提交表单的效果 <!DOCTYPE html> <html lang="en"&g ...

  10. SC OpenService 失败5:拒绝访问

    当我们在cmd里使用 sc delete  服务名  ,来删除服务的时候,报错误,SC OpenService 失败5:拒绝访问. 这似乎是因为权限不够,解决方法. 首先,我们必须先取得管理员权限,以 ...