一、引言

  在C#中,静态和非静态的特征对于我们来说是再熟悉不过了,但是很少看到有一篇文章去好好地总结静态和非静态它们之间的不同,为了帮助大家更好地去理解静态和非静态特征, 所以将在这篇文章中帮大家全面总结下它们之间的不同,包括静态类,静态成员和静态构造函数。希望在大家巩固基础的时候可以拿出来好好复习下的。下面废话不多了,直接进入我们今天的主题。

二、为什么需要静态特征

  在自定义类或看.NET Framework类库中都可以发现,类中大部分都是具体实例特征(也就是没有static标识的),同时我们也能看到一些具有静态特征的类或成员,例如我们经常使用的Console类以及WriteLine方法就是静态的。然而有些朋友会疑惑,为什么还要有静态特征的呢?干脆都定义为实例的好了? 然后静态特征的存在肯定有它存在的原因的,并不是我们就是要这么定义的,其实我一直认为不管是什么都是源于生活的, 技术的实现也是一样,比如我们开发程序,需要掌握技术外,其实更重要的是业务逻辑这块的,如果你都不知道你开发的东西是怎样的一个流程,即使你技术再牛做出来的东西都是反人类的东西(也就是指不符合用户的用户习惯和之前的一个业务需求),其实静态特征的存在也是源于生活的,对于类好比就是我们现实生活中的人或事物,静态特征和非静态特征就好比生活中人或事物具有的特征, 我们询问人的时候或者电视剧警察查案件的时候,都会听到这样一句话 "那个人有什么特征?"或 “嫌疑犯有什么特征?多高,年龄等” 其实高度、年龄、性别都是一个人的特征,所以这些在语言范畴就需要为其进行定义了,也就是我们定义的实例成员了,然而有些特征需要被所有对象实例所共有的,这些特征在语言范畴就定义为静态特征,具体哪些特征可以定义为静态特征呢? 其实这点一样是源于生活的,所以我们在开发软件的过程中,必不可少的一个流程就是需求分析了,只有在了解客户需求的条件下才能进行之后的所有流程的, 例如一个班级有很多学生,每个学生是一个实体,在语言范畴就可以定义一个类,当我们需要一个学生的时候就可以通过new 关键字创建一个出来(说到这里又让我想到了恶搞泰囧的图片——你有对象吗?没对象,你们程序员可以自己new一个啊?),然而我们创建出来的学生他们都有一些共有的特征,如同一个班级,学校等, 如果我们把班级、学校这样的特征也定义为实例的话,那么我们不是每次创建对象实例的时候都为这些共有的特征分配一次内存的,这样不仅对内存空间的浪费也是不满足生活常识的,此时我们就可以把班级、学校这样的特征定义为静态特征,这样所有实例都可以共享这两个特征,并且不需要为每个对象实例分配内存

三、比较静态特征和非静态特征

3.1 静态类与非静态类

  • 静态类和非静态类在C#中定义基本是一样的,只是静态类定义需要加上static修饰符而已。下面就直接总结下它们之间的区别:
  • 静态类只能包含静态成员,否则会抛出编译错误;然而非静态类既可以包含非静态成员也可以包含静态成员
  • 静态类是不能实例化,之所以不能实例化,是因为静态类会导致C#编译器将该类同时标记为abstract和sealed,并且编译器不会在类型中生成一个实例的构造函数,从而导致静态类不能实例化,具体原因可以见下图;非静态类可以,并且静态成员的访问只能通过类来进行访问,因为静态成员是属于类的。
 public static class StaticClass
{
private static string name;
}

上面代码用IL反汇编程序得到的IL代码结构为:

3.2 静态构造函数与实例构造函数

  • 静态构造函数用来初始化类中的静态成员的,包括静态字段和静态属性,并且静态构造函数是不能带有参数、不能有访问修饰符,静态构造函数的调用是由CLR第一次调用类成员之前执行的。
  • 下面还是直接总结下静态构造函数与实例构造函数之间的区别:
  • 静态构造函数可以与无参的实例构造函数同时存在
  • 静态构造函数在CLR加载类时执行,然而实例构造函数在每次实例创建时都会执行
  • 静态构造函数只能对静态成员初始化,不能对非静态成员进行初始化操作,然而实例构造函数,既可以初始化实例成员也可以初始化静态成员,但静态只读字段除外
  • 静态构造函数只被执行一次,但是CLR也不能确定它什么时候被执行,它的执行方式有两种,precise和before-field-init,这个会在下一篇文章中详细给大家介绍,这里先提出给大家一个思考的空间。而实例构造函数在每次创建对象实例时都会被执行,创建几个就会执行几次
  • 一个类只能有一个静态构造函数,却可以有多个实例构造函数

静态字段的初始值在静态构造函数调用之前被指定,构造函数的执行顺序大致如下图所示:

3.3 静态字段、属性和实例字段、属性

下面就直接总结下它们之间的区别:

  • 静态成员包括静态字段和静态字段,静态字段一般实现为private,静态属性一般实现为public,从而来体现类的封装性
  • 静态成员和类相关联,不依赖于对象而存在,只能由类来访问;实例成员与具体类相关联,只能由对象实例访问
  • 静态成员不管创建多少实例对象,都在内存中只有一份,实例成员每创建一个实例对象,都会在内存中分配一块内存区域。

3.4 静态方法与实例方法

类似于静态字段和属性,静态方法共享代码段,同样以static关键字来标识静态方法,对于他们之间的区别总结为:

  • 静态方法只能访问静态成员和方法,但是可以间接通过创建实例对象来访问实例字段、属性和方法;实例方法既可以访问实例成员也可以访问静态成员
  • 静态方法由类方法‘实例方法由对象访问
  • 静态方法不能引用this关键字,而实例方法可以
  • 静态方法不能被标识为virtual、abstract或override,静态方法可以被派生访问,但是不能被派生类重写
  • Main方法为静态的,所以Main方法不能直接访问类中的实例字段、属性和方法,否则编译器会报错
  • 静态方法一般用于作为通用的工具类来实现
  • 在性能上,静态方法和实例方法的差别不大。因为,它们都是在JIT加载类的时候分配内存的,不同的是静态方法是以类为引用,而实例方法是以对象为引用,创建实例时,不会再为静态方法分配内存,所有实例对象共用一个类的方法代码,所以,静态方法和实例方法的调用,区别仅在于静态方法可以直接调用,而实例方法需要当前对象指针指向该方法,在性能上差不并不大。

四、小结

  到这里,本文章的内容就介绍完了,通过对静态特征和非静态特征的由来来揭开一些都是源于生活的观点,然后再详细分析了静态特征与非静态特征在C#语言中的区别,希望这些总结可以帮助大家在复习基础知识的时候可以有用。同时也是自己的一个复习笔记的。

C#中静态方法和非静态方法的区别(二)的更多相关文章

  1. 转 C#中静态方法与非静态方法区别比较

    C#静态方法与非静态方法的区别不仅仅是概念上的,那么他们有什么具体的区别呢?让我们通过本文向你做一下解析. C#的类中可以包含两种方法:C#静态方法与非静态方法.那么他们的定义有什么不同呢?他们在使用 ...

  2. C#中静态方法和非静态方法的区别

    静态方法和非静态方法的区别: 1.静态方法不需要类实例化就可以调用,反之非静态方法需要实例化后才能调用: 2.静态方法只能访问静态成员和方法,非静态方法都可以访问: 3.静态方法不能标记为overri ...

  3. Java中synchronized用在静态方法和非静态方法上面的区别

    synchronized 修饰在 static方法和非static方法的区别   在Java中,synchronized是用来表示同步的,我们可以synchronized来修饰一个方法.也可以sync ...

  4. C#中静态与非静态方法比较

    C#静态方法与非静态方法的区别不仅仅是概念上的,那么他们有什么具体的区别呢?让我们通过本文向你做一下解析. C#的类中可以包含两种方法:C#静态方法与非静态方法.那么他们的定义有什么不同呢?他们在使用 ...

  5. C#中静态与非静态方法比较【转】

    C#静态方法与非静态方法的区别不仅仅是概念上的,那么他们有什么具体的区别呢?让我们通过本文向你做一下解析. C#的类中可以包含两种方法:C#静态方法与非静态方法.那么他们的定义有什么不同呢?他们在使用 ...

  6. c#静态方法和非静态方法区别

    c#静态方法和非静态方法区别 C#的类中可以包含两种方法:C#静态方法与非静态方法.那么他们的定义有什么不同呢?他们在使用上会有什么不同呢?让我们来看看最直观的差别:使用了static 修饰符的方法为 ...

  7. Java中堆、栈,静态方法和非静态方法的速度问题

           一.堆和栈的速度性能分析 堆和栈是JVM内存模型中的2个重要组成部分,自己很早以前也总结过堆和栈的区别,基本都是从存储内容,存储空间大小,存储速度这几个方面来理解的,但是关于堆和栈的存储 ...

  8. 在java中静态方法与非静态方法

    在java中public void与public static void有什么区别 ? public void 修饰是非静态方法,该类方法属于对象,在对象初始化(new Object())后才能被调用 ...

  9. <转>java中静态方法和非静态方法的存储

    Java中非静态方法是否共用同一块内存? 将某 class 产生出一个 instance 之后,此 class 所有的 instance field 都会新增一份,那么所有的 instance met ...

  10. 在静态方法和非静态方法上加 Synchronized的区别

    Synchronzied 修饰非静态方法==>对象锁 Synchronzied 修饰静态方法==>其实是类锁,因为是静态方法,它把整个类锁起来了: 1.Synchronized修饰非静态方 ...

随机推荐

  1. luajit 安装cjson

    最近需要升级原有服务器的nginx加载逻辑,新的lua脚本需要解析一个远程返回的json格式的结果,原有的luajit并没有带cjson库,需要自己手动安装一下. 基本参考博客luajit安装cjso ...

  2. AngularJS的开发工具---yeoman 简易安装

    AngularJS 不错,yeoman作为推荐开发工具,网上的安装步骤较烦,这里给出简易步骤. 1.安装 Ruby     自己到 Ruby 官方下载最新安装包: http://rubyinstall ...

  3. 【Android - MD】之TabLayout的使用

    TabLayout是Android 5.0新特性--Material Design中的一个控件,是一个标签页的导航条,常结合ViewPager完成页面导航. 和其他MD控件一样,使用TabLayout ...

  4. 弹出窗口zDialog的使用

    因为没有元素可以显示到Frameset上面去,所以重新定义了,一个index.htm,对其的操作是: Index.htm    <script language="javascript ...

  5. C# 打开PPT文件另存为PPTX

    /// <summary> /// rename PPT /// </summary> private static void renamePPT() { //add refe ...

  6. QStandardItemModel角色控制及QTreeView加入不同的右键菜单

    1.概述 QTreeView最长用的一个功能就是作为导航栏,像vs里的项目结构树,word的文档结构图,资源管理器的文档结构,等等都是利用树形结构组织的,在前面已经讲述了Qt中使用标准化项目模型QSt ...

  7. MapReduce优化

    Combiner和Partitioner是用来优化MapReduce的,可以提高MapReduce的运行效率.下面我们来具体学习这两个组件 Combiner 我们以WordCount为例,首先通过下面 ...

  8. 动态添加子视图 UIView 的正确方法

    很多时候哥比较喜欢用代码添加视图,特别是要同时加很多UIView时,而且跟 xib 比起来代码更容易管理,在多人的项目中代码不容易 conflict. 但小牛哥最近发现很多新人都不太清楚正确的使用方法 ...

  9. Servlet 过滤器

    一.过滤器介绍 在Servlet 2.3中定义了过滤器,它能够对Servlet容器的请求和响应进行检查和修改. Servlet过滤器能够在Servlet被调用之前检查Request对象,并修改Requ ...

  10. Linux sed命令常用方法

    sed也成stream editor,流编辑器,是Linux上常用的文本处理工具. 通用格式:sed  行范围  模式/RegExp/  文件 模式: d 删除 p 打印符合条件的行 a \strin ...