今天跟大家分享一下关于访问限定和数据成员的知识。主要包括以下两点:

  • Abstract, sealed, virtual, new, override怎么用?
  • Const 和 readonly好像都表示不能改变的值,有什么区别呢?

一、 访问限定

类和方法有一些访问限定符,如private,public等。除此之外,还包含一些预定义特性。下面几个你都知道吗?

1. 类的预定义特性
  • Abstract——抽象类。不能实例化。如果派生类不是抽象类,则必须实例化。
  • Sealed——密封类。不能做基类被继承。

要想既不能实例化又不能被继承? 需要两个步骤:

  1. seadled修饰。防止被被继承 ;
  2. 私有化无参构造器。防止实例化自动调用默认无参构造函数。例如:

sealed class Demo

{

private Demo() { }

...

}

2. 方法的预定义特性
  • Abstract——用于抽象类中的抽象方法,该方法不能包含具体实现。派生类如果不实现该方法,则必须为抽象类。

public abstract class Animal

{

public abstract void Shout();

}

  • Virtual——用于非静态方法。调用时实现的是继承链最末端的方法,也就是按照运行时类型调用的,而不是编译时类型。
  • New——隐藏但并不会改变基类中虚方法的实现。(调用的时候,类型是父类时,调用父类的方法;类型是子类时,调用的是子类的方法)
  • Override——重写基类中的虚方法。

实例:

public class Animal //基类
    {

public virtual void Shout()     //定义虚方法
        {

Console.WriteLine("逼我发威啊!"); //虚方法实现

}

}

public class Dog : Animal  
    {

public override void Shout()    //override重写基类方法
        {

Console.WriteLine("汪汪!");

}

}

public class Cat : Animal
    {

public new void Shout()        //new隐藏基类方法
        {

Console.WriteLine("喵喵~~");

}

}

class Program
    {

static void Main(string[] args)
        {

new Animal().Shout();   //“逼我发威啊!”

new Dog().Shout();        //“汪汪!”

new Cat().Shout();        //”喵喵~~”

Console.WriteLine("**************************");

Animal a1 = new Dog();

a1.Shout();                  //重写了基类的方法   “汪汪!”

Animal a2 = new Cat();

((Cat)a2).Shout();       //派生类中的方法隐藏了基类的方法 ”喵喵~~”(类型是子类Cat)

a2.Shout();                 //基类的方法没有被修改,只是被隐藏 “逼我发威啊!”(类型是父类Animal)

Console.Read();

}

}

二、 数据成员——常量和只读

我们经常提到常量和只读,听上去都是不能改变的意思,那么它们到底有什么区别呢?
1. 常量const

常量是恒定不变的,在编译时就确定了它的值,编译后直接将值存到元数据中。变量类型只能是编译器能直接识别的基元类型,不能是引用类型,因为引用类型需要在运行时调用构造函数进行初始化。

我们给段代码实际看一下:

class TestConst    
   {
       public const int Number = 100;     //声明常量并赋值
       public string GetName()
       {
           const string name = "XiaoJing";    //常量用作局部变量
           return name;
       }
   }

class Program
   {

static void Main(string[] args)
       {
           Console.WriteLine("const:The total number is " + TestConst.Number);
           Console.Read();
       }
   }

通过ILDasm工具查看一下,const变量编译后为static literal类型,所以不难理解,常量是针对类的一部分,而不是实例的一部分。这样它才能保证是恒定不变的。

在使用常量时,编译器从常量模块的元数据中直接取出常量的值,嵌入到IL代码中。所以在声明常量的时候就要为它初始化值。例如上面的例子,Number直接替换为值100。

Main函数的IL代码如下:

还有一点,const常量也可以用于局部变量,例如上面的GetName()方法。

2. 只读字段readonly

类的数据成员通常用来保存一个值类型的实例或者指向引用类型的引用,CLR支持读写和只读两种数据成员,其中只读数据成员使用readonly修饰的。看个实际例子:

class TestReadonly
  {
      public readonly int Number = 100;   //只读实例成员
      public TestReadonly()
      {
          Number = 200;         //构造器中重新赋值
      }
  }

class Program
  {
      static void Main(string[] args)
      {
          Console.WriteLine("readonly:The total number is " + new TestReadonly().Number);
          Console.Read();
      }
  }

通过ILDasm.exe工具查看, Readonly实例成员编译后为 initonly修饰。这个例子是只读实例成员,readonly也可以修饰静态只读成员,需要在类静态构造器中初始化,这里就不赘述了。

数据成员是在类的实例构造过程中分配内存的,因此能在运行时刻获取它的值。因此只读成员类型没有限制,可以是基元类型,也可以是引用类型。而且可以在构造器中赋值,声明时赋值与否都可以。

我们查看main函数的IL代码:可以看出首先对TestReadonly类进行实例化,然后读取实例的Number成员的值,是在运行过程中获取值的。

还有要注意的一点,readonly不能用作局部变量,否则编译时就会报错。

最后我们要说明的是,readonly字段不能改变的是引用,而不是字段引用的对象。例如


public sealed class AType
    {
        public static readonly char[] chars = new char[] { 'a', 'b', 'c' };
    }
    public sealed class BType
    {
        public static void Change()
        {
            AType.chars[0] = 'X';
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(AType.chars[0]);
            BType.Change();
            Console.WriteLine(AType.chars[0]);
            Console.Read();
        }
    }

运行结果是

a

X

CLR via C#(05)- 访问限定、数据成员的更多相关文章

  1. 《Effective C#》读书笔记-1.C# 语言习惯-1.使用属性而不是可访问的数据成员

    思维导图: 大纲: 1.使用属性而不是可访问的数据成员    属性        指定不同的访问权限        隐式属性降低了声明属性的工作量        允许将数据成员作为公共接口的一部分暴露 ...

  2. 改善 C# 的语言习惯(一) - 使用属性而不是可访问的数据成员(整理中)

    改善 C# 的语言习惯(一) - 使用属性而不是可访问的数据成员 序 为什么我们的程序运行得棒棒的,还要改呢?Why? 答:我们要让程序运行得更快,执行的效率更高,代码的可读性更强,维护的成本更低.. ...

  3. 《C#高效编程》读书笔记01-使用属性而不是可访问的数据成员

    在需求变更中,属性比数据成员更容易修改,例:客户对象不该与空白名称,若你使用公有属性封装Name,那么现在修改一处,而数据成员则可能要修改多处 public class Customer { priv ...

  4. 3第一周课后练习·阅读计划(2)-使用指针来访问私有数据成员

    /* * Copyright (c) 2015, 计算机科学学院,烟台大学 * All rights reserved. * 文件名:test.cpp * 作 靠:刘畅 * 完成日期:2015年 3 ...

  5. 3第一周课后练习·阅读计划(3)-使用函数来访问私有数据成员

    /* * Copyright (c) 2015, 计算机科学学院,烟台大学 * All rights reserved. * 文件名:test.cpp * 作 靠:刘畅 * 完成日期:2015年 3 ...

  6. C++类中的常数据成员和静态数据成员的区别

    刚开始学习C++的类和对象的部分,对类中的常数据成员和静态数据成员的概念和用法经常混淆,所以今天整理一下,顺便说一下,今天是我的生日,祝我生日快乐,呵呵. 常数据成员 常数据成员是指在类中定义的不能修 ...

  7. C++基础(静态数据成员和静态成员函数)

    [简介] 1.静态数据成员在类中声明,在源文件中定义并初始化: 2.静态成员函数没有this指针,只能访问静态数据成员: 3.调用静态成员函数:(1)对象.(2)直接调用: 4.静态成员函数的地址可用 ...

  8. 【C++】私有数据成员不能用对象去访问吗

    首先,必须清楚的是private和public限定的是类而不是对象.因此,在成员函数中访问同类对象的私有成员是完全可以的. 所以,某些教材上所说的“私有数据成员不能用对象去访问”是欠妥当的. 比如,如 ...

  9. Java中public、private、protect对数据成员或成员函数的访问限制

    Java类中对数据成员.成员函数的访问限制修饰有:public.protect.private.friendly(包访问限制) public修饰的数据成员或成员函数是对所有用户开放的,所有用户可以直接 ...

随机推荐

  1. Inorder Successor in Binary Search Tree

    Given a binary search tree (See Definition) and a node in it, find the in-order successor of that no ...

  2. Android坐标系统

     1 背景 去年有很多人私信告诉我让说说自定义控件,其实通观网络上的很多博客都在讲各种自定义控件,但是大多数都是授之以鱼,却很少有较为系统性授之于渔的文章,同时由于自己也迟迟没有时间规划这一系列文章, ...

  3. hiho一下 第一百零七周 Give My Text Back(微软笔试题)

    题目1 : Give My Text Back 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 To prepare for the English exam Littl ...

  4. mysql 之基本操作

    已经在板子内部把所有的环境都搭好了,现在的要求是对Mysql 进行一些基本的操作. 在这之前,记录几个要点以防以后忘记. 一,准备工作. 1. 将usr/share/mysql 目录下的 my-lag ...

  5. (七)理解angular中的module和injector,即依赖注入

    (七)理解angular中的module和injector,即依赖注入 时间:2014-10-10 01:16:54      阅读:63060      评论:1      收藏:0      [点 ...

  6. Java获取新浪微博cookies

    import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.F ...

  7. 【实例】html5-canvas中实现背景图片的移动

    本例来自于<HTML5 Canvas核心技术 图形.动画与游戏开发> 在线演示 (图有点多,请多刷新几次) 本例还有一点代码不理解,我用注释和问号标注出来了,有大神看到求解答,谢谢 本例子 ...

  8. phalcon 前端代码结构

    phalcon 前端举例: (1)  baisic.phtml + basic_ajax_get.phtml + basic_ajax_post.phtml (2)  basic_get.phtml ...

  9. Vim保存只读模式下的修改

    用 vim 打开没有写权限的文件而忘记用 sudo 时,文件变成 read-only这时候用 :w!, SHIFT+ZZ,或者 qw! 都无法保存 :w !sudo tee % :w : Write ...

  10. 【GoLang】go 微服务框架 && Web框架学习资料

    参考资料: 通过beego快速创建一个Restful风格API项目及API文档自动化:  http://www.cnblogs.com/huligong1234/p/4707282.html Go 语 ...