6.C#类以及类成员详解(新)

一、类的相关概念:

1)、对象:现实世界中的实体(世间万物皆对象),类:具有相似属性和方法的对象的集合。

☆相互关系:类是对象的抽象,对象是类的实例,类是一种抽象的分类,对象则是具体事物。

2)、类的三大特性:继承、封装、多态

3)、对象的三要素:属性(对象是什么)、方法(对象能做什么)、事件(对象如何响应)

二、C#类与命名空间

①同一命名空间的可以随便访问不受限制

②子命名空间可以访问父命名空间

③引用命名空间或者命名空间.类也可访问不同命名空间的类

三、类的可访问性

(1)、类修饰符

类的声明格式如下:

属性 类修饰符  class  类名  {类体}

其中class、类名和类体是必需的,其他是可选项。类修饰符包括 new、public、protected、private、internal、abstract、sealed等。

可访问性

含义

public

访问不受限制

protected

访问仅限于此类和从此类派生的类

internal

访问仅限于此程序

protected internal

访问仅限于此程序和从此类派生的类

private

访问仅限于此类

注:类成员只有为public和internal和protected  internal才能被其他并列关系的类引用。

可访问性

含义

Partial

部分类,可以将一个类分成几部分写在不同文件中,最终编译时将合成一个文件,并且各个不能分散在不同的程序集中

Abstract

抽象类,不能创建该类的实例,修饰方法的时候表示该方法需要由子类来实现,如果子类没有实现该方法那么子类同样是抽象类;且含有抽象方法的类一定是抽象类

Sealed修饰类时表示该类不能被继承,修饰方法时表示该方法不能被复写
Virtual

修饰方法成员,表示虚方法,父类可以含有各类的实现,子类可以重写该函数

Static修饰类的时候表示该类为静态类,所有的成员都是静态成员,调用类中成员的时候不能被实例化。修饰成员的时候,表示为静态成员,调用该成员类不能实例化,但是其他的成员可以

(2)、类的继承

如果已经存在person类,还想再定义一个雇员类,可以以person类为基类,派生出一个雇员类employee。

派生类的声明格式如下:

属性  类修饰符   class  派生类名:基类名{类体}

C#语言类继承的特点:

①只允许单继承,即派生类只能有一个基类。

②派生类继承可传递。

③派生类可继承基类的属性,但是不能继承构造函数、析构函数和事件。

④派生类可以覆盖基类的同名成员。

⑤派生类对象也是其基类的对象,反之不成立。

(3)、类的多态性

C#支持两种类型的多态性:

①一个类的对象调用若干同名方法。根据调用方法的实参类型及实参个数决定调用哪个同名方法。

②运行时的多态性。在系统运行时,不同对象调用同一个名字相同、参数的类型和个数完全一样的方法,会完成不同的操作。C#运行时的多态性通过虚方法实现。

public class Person
    {
        private string P_Name = "张三";//私有字段
        private int P_Age = 12;
        public string Name//定义属性
        {
            get { return P_Name; }
            set { P_Name = value; }
        }
        public int Age//定义属性
        {
            get { return P_Age; }
            set { P_Age = value; }
        }
        public Person(string name,int age)
        {
            Name = name;
            Age = age;
        }
        public void Display()
        {
            Console.WriteLine("姓名{0},年龄{1}",P_Name,P_Age);
        }
        static public void DIsplayData(Person person){
            person.Display();
        }

    }
    public class Employee:Person
    {
        private string department;
        private decimal salary;
        public Employee(string Name,int Age,string Department,decimal Salary):base(Name,Age){
            department=Department;
            salary=Salary;
        }
       public override void Display(){//重载虚方法,注意用override
           base.Display();
           Console.WriteLine("部门:{0}  薪金:{1}",department,salary);
       }
    }
    public class Class1
    {
        static void Main(string[] args)
        {
            Person person = new Person("李四", 30);
            Person.DIsplayData(person);
            Employee emp = new Employee("张三",25,"技术研发部",100000);
            Person.DIsplayData(emp);
        }
    }

    //输出结果:
    //姓名:李四,年龄:30
    //姓名:张三,年龄:25
    //部门:技术研发部 薪金:100000

(4)、抽象类和抽象方法

抽象类表示一种抽象的概念,只是希望以它为基类的派生类有共同的函数成员和数据成员,对抽象类有以下几点规定:

☆ 抽象类只能作为其他类的基类,不能被实例化。

☆ 抽象类允许包含抽象成员,虽然不是必须的。

☆ 抽象类不能同时又是密封的。

☆ 抽象类的基类也可以是抽象类,如果一个非抽象类的基类是抽象类,则该类必须通过覆盖一来实现所有继承而来的抽象方法,包括抽象基类中的方法。

   abstract class Figure//抽象类定义
    {
        protected double x = 0, y = 0;
        public Figure(double a ,double b)
        {
            x = a;
            y = b;
        }
        public abstract void Area();//抽象方法,无实现代码
    }
    class Square : Figure
    {
        public Square(double a, double b)
            : base(a,b)
        {

        }
        public override void Area()//不能用new,必须用override
        {
            Console.WriteLine("矩形的面积是:{0}",x*y);
        }
    }
    class Circle : Figure
    {
        public Circle(double a)
            : base(a,a)
        {

        }
        public override void Area()
        {
            Console.WriteLine("圆形的面积是:{0}",3.14*x*y);
        }
    }
    class Class1
    {
        static void Main(string[] args)
        {
            Square s = new Square(20,30);
            Circle c = new Circle(10);
            s.Area();
            c.Area();
        }
    }

(5)、密封类和密封方法

有时候开发者并不希望自己编写的类被继承,或者有的类已经没有再被继承的必要。C#提出了一个密封类的概念,帮助开发人员来解决这一问题。密封类使用sealed修饰符。如果试图讲一个密封类作为其他类的基类,C#编译器将提示出错。理所当然,密封类不能同时是抽象类,因为抽象类总是希望被继承的。

C#还提出了密封方法的概念,在派生类中,不能覆盖基类中的密封方法。

四、类的成员

(1)、类的成员可以分为两大类:类本身声明的以及从基类中继承来的。

类的成员有:局部变量、字段、属性、构造函数、析构函数、方法成员、事件、索引指示器、操作符重载、事件。

public class List
{

    const int defaultCapacity = 4;

常量

    object[] items;
    int count;

字段

    public List(): List(defaultCapacity) {}

    public List(int capacity) {
       items = new object[capacity];
    }

构造函数

    public int Count {
       get { return count; }
    }

    public string Capacity {
       get {
           return items.Length;
       }
       set {
           if (value < count) value = count;
           if (value != items.Length) {
              object[] newItems = new object[value];
              Array.Copy(items, 0, newItems, 0, count);
              items = newItems;
           }
       }
    }

属性

    public object this[int index] {
       get {
           return items[index];
       }
       set {
           items[index] = value;
           OnListChange();
       }
    }

索引器

    public void Add(object item) {
       if (count == Capacity) Capacity = count * 2;
       items[count] = item;
       count++;
       OnChanged();
    }

    protected virtual void OnChanged() {
       if (Changed != null) Changed(this, EventArgs.Empty);
    }

    public override bool Equals(object other) {
       return Equals(this, other as List);
    }

    static bool Equals(List a, List b) {
       if (a == null) return b == null;
       if (b == null || a.count != b.count) return false;
       for (int i = 0; i < a.count; i++) {
           if (!object.Equals(a.items[i], b.items[i])) {
              return false;
           }
       }
      return true;
    }

方法

    public event EventHandler Changed;

事件

    public static bool operator ==(List a, List b) {
       return Equals(a, b);
    }

    public static bool operator !=(List a, List b) {
       return !Equals(a, b);
    }

运算符

}

(2)、类成员访问修饰符

访问修饰符用于指定类成员的可访问性,共四种如下:

可访问性

含义

public

声明共有成员、可以被类的外部程序调用。实际上是一个类和外部通讯的接口,外部程序通过调用公有函数,按照预先设定好的方法来修改类的私有成员和保护成员。

protected

声明保护成员,数据成员和函数成员只能被类内部和派生类的函数使用和修改。

internal

声明内部成员,只能在同一程序集中的文件才是可以访问的,一般是同一个应用(Application)或库(Library)。

private

声明私有成员,只能被类内部的函数修改和使用;派生类虽然继承了基类的私有成员,但不能直接访问他们,只能通过基类的公有成员访问。

(3)、成员介绍

类的字段和属性:

①静态字段、实例字段、常量、只读字段:

☆ 使用 static 修饰符声明的字段定义了一个静态字段 (static field)。一个静态字段只标识一个存储位置。对一个类无论创建了多少个实例,它的静态字段永远都只有一个副本。

☆ 不使用 static 修饰符声明的字段定义了一个实例字段 (instance field)。类的每个实例都包含了该类的所有实例字段的一个单独副本。

☆ 用const修饰符声明的字段为常量,常量只能在声明中初始化,以后不能再修改。

☆ 用readonly 修饰符声明的字段是只读字段,是特殊的实例字段,只能在字段声明或者构造函数中重新赋值,在其他任何地方都都不能改变只读字段的值

示例如下:

 public class Test
    {
        public const int intMax = int.MaxValue;//常量,必须赋初值
        public int x = 0;//实例字段
        public readonly int y = 0;//只读字段
        public static int cnt = 0;//静态字段
        public Test(int x1,int y1)//构造函数
        {
            //intMax = 0;//错误,不能改变常量
            x = x1;//构造函数中允许修改实例字段
            y = y1;//构造函数中允许修改只读字段
            cnt++;//每创建一个对象都调用构造函数,此语句可以记录对象的个数
        }
        public void Modify(int x1,int y1){
            //intMax = 0;//错误,不能修改常量
            x = x1;//
            //y = 10;//不允许修改只读字段
            cnt=y1;//
        }
    }
    class Class1
    {
        static void Main(string[] args)
        {
            Test T1 = new Test(100,200);
            T1.x = 40;
            Test.cnt = 0;//类名.静态字段名
            int z = T1.y;//引用只读字段
            z = Test.intMax;//引用常量
        }
    }
//在下面的示例中,Color 类的每个实例都有实例字段 r、g 和 b 的单独副本,
//但是 Black、White、Red、Green 和 Blue 静态字段只存在一个副本:

public class Color
{
public static readonly Color Black = new Color(0, 0, 0);
public static readonly Color White = new Color(255, 255, 255);
public static readonly Color Red = new Color(255, 0, 0);
public static readonly Color Green = new Color(0, 255, 0);
public static readonly Color Blue = new Color(0, 0, 255);

private byte r, g, b;

public Color(byte r, byte g, byte b) {
     this.r = r;
     this.g = g;
     this.b = b;
}
}
//this代表当前对象

②属性

属性与字段的关联与区别

1.属性不是字段,但必然和类中的某个或某些字段相关联,属性定义了得到和修改相关联系的字段的方法。充分地体现了类的封装性,不直接操作类的数据结构,而是通过访问器进行访问。

  public class Person
    {
        private string P_Name = "张三";//私有字段
        private int P_Age = 12;
        public string Name//定义属性
        {
            get { return P_Name; }
            set{P_Name=value;}
        }
        public int Age//定义属性
        {
            get { return P_Age; }
            set { P_Age = value; }
        }
        public void Display()
        {
            Console.WriteLine("姓名{0},年龄{1}",P_Name,P_Age);
        }
    }
    public class Test1
    {
        static void Main(string[] args)
        {
            Person person = new Person();
            person.Name = "鸸鹋";
            person.Age = 24;
            person.Display();
        }
    }

2.属性可以对值进行限制,字段则不行

public class Employee
{
public int age
{
get { return age; }
set {
     if(value >= 18 && value<=60)
     age = value;
    }
};
public string name;
Public Employee(int age,string name){
This.age=age;
This.name=name;
}
}

 

构造函数:

C# 支持两种构造函数:实例构造函数和静态构造函数。实例构造函数 (instance constructor) 是实现初始化类实例所需操作的成员。静态构造函数 (static constructor) 是一种用于在第一次加载类本身时实现其初始化所需操作的成员。

构造函数的声明如同方法一样,不过它没有返回类型,并且它的名称与其所属的类的名称相同。如果构造函数声明包含 static 修饰符,则它声明了一个静态构造函数。否则,它声明的是一个实例构造函数。

实例构造函数可以被重载。例如,List 类声明了两个实例构造函数,一个无参数,另一个接受一个 int 参数。实例构造函数使用 new 运算符进行调用。下面的语句分别使用 List 类的每个构造函数分配两个 List 实例。

List list1 = new List();
       List list2 = new List(10);

实例构造函数不同于其他成员,它是不能被继承的。一个类除了其中实际声明的实例构造函数外,没有其他的实例构造函数。如果没有为某个类提供任何实例构造函数,则将自动提供一个不带参数的空的实例构造函数。

析构函数:

析构函数 (destructor) 是一种用于实现销毁类实例所需操作的成员。析构函数不能带参数,不能具有可访问性修饰符,也不能被显式调用。垃圾回收期间会自动调用所涉及实例的析构函数。

垃圾回收器在决定何时回收对象和运行析构函数方面允许有广泛的自由度。具体而言,析构函数调用的时机并不是确定的,析构函数可能在任何线程上执行。由于这些以及其他原因,仅当没有其他可行的解决方案时,才应在类中实现析构函数。

类的方法:

  方法的声明格式如下:

        属性  方法修饰符  返回类型  方法名(形参列表){方法体}

1.方法的修饰符包括new、public、protected、internal、private、static、virtual、sealed、override、abstract、extern。

2返回类型可以使任何合法的C#数据类型。

3.静态方法 (static method) 通过类来访问。实例方法 (instance method) 通过类的实例来访问。

4.方法具有一个参数 (parameter) 列表(可能为空),表示传递给该方法的值或变量引用;方法还具有一个返回类型 (return type),指定该方法计算和返回的值的类型。如果方法不返回值,则其返回类型为 void。

<1>方法参数的种类

①值参数(无修饰符)

②引用参数(ref):实参变量要求必须设置初始值

③输出参数(out)

④数组参数(params)

数组参数只允许是一维数组,且不能再有ref和out修饰符。

class Class1
    {
        static void F(params int[] args)
        {
            Console.WriteLine("Array contains {0} elements: ",args.Length);
            foreach (int i in args)
            {
                Console.Write(" {0}",i);
                Console.WriteLine();
            }
        }

        static void Main(string[] args)
        {
            int[] a = { 1, 2, 3 };
            F(a);//  1 2 3
            F(10,20,30,40);// 10 20 30 40
            F(new int[]{60,70,80,90});// 60,70,80,90
            F();//
            F(new int[]{});//
        }
    }

<2>静态方法和实例方法

由于使用静态方法时,该静态方法使用的类可能还没有对象,即使有对象,由于用【类名.静态方法名】方式调用静态方法,静态方法没有this指针来存放对象的地址,无法判断访问哪个对象的数据成员,所以静态方法只能使用所在类的静态数据成员和静态方法。只有类在创建对象后,实例方法才能被使用。而实例方法既可以访问静态成员也可以访问实例成员。

静态类下的成员全是静态成员。

<3>方法重载

        方法的签名 (signature) 在声明该方法的类中必须唯一。方法的签名由方法的名称及其参数的数目、修饰符和类型组成。方法的签名不包含返回类型。

操作符重载:

操作符重载实际上是定义了一个操作符函数,声明格式如下:

static public 函数返回类型 operator 重新定义的操作符(形参表)

eg:

static public Complex  operator -(Complex a){

return (new  Complex(-1,-2));

}

索引器

索引器 (indexer) 是这样一个成员:它使对象能够用与数组相同的方式进行索引。索引器的声明与属性类似,不同的是该成员的名称是 this,后跟一个位于定界符 [ 和 ] 之间的参数列表。在索引器的访问器中可以使用这些参数。与属性类似,索引器可以是读写、只读和只写的,并且索引器的访问器可以是虚的。

该 List 类声明了单个读写索引器,该索引器接受一个 int 参数。该索引器使得通过 int 值对 List 实例进行索引成为可能。例如

List numbers = new List();
names.Add("Liz");
names.Add("Martha");
names.Add("Beth");
for (int i = 0; i < names.Count; i++) {
string s = (string)names[i];
names[i] = s.ToUpper();
}

索引器可以被重载,这意味着一个类可以声明多个索引器,只要它们的参数的数量和类型不同即可。

事件

事件 (event) 是一种使类或对象能够提供通知的成员。事件的声明与字段类似,不同的是事件的声明包含 event 关键字,并且类型必须是委托类型。

在声明事件成员的类中,事件的行为就像委托类型的字段(前提是该事件不是抽象的并且未声明访问器)。该字段存储对一个委托的引用,该委托表示已添加到该事件的事件处理程序。如果尚未添加事件处理程序,则该字段为 null。

List 类声明了一个名为 Changed 的事件成员,它指示有一个新的项已被添加到列表中。Changed 事件由 OnChanged 虚方法引发,后者先检查该事件是否为 null(表明没有处理程序)。“引发一个事件”与“调用一个由该事件表示的委托”完全等效,因此没有用于引发事件的特殊语言构造。

客户端通过事件处理程序 (event handler) 来响应事件。事件处理程序使用 += 运算符添加,使用 -= 运算符移除。下面的示例向 List 类的 Changed 事件添加一个事件处理程序。

using System;

class Test
{
static int changeCount;

static void ListChanged(object sender, EventArgs e) {
     changeCount++;
}

static void Main() {
     List names = new List();
     names.Changed += new EventHandler(ListChanged);
     names.Add("Liz");
     names.Add("Martha");
     names.Add("Beth");
     Console.WriteLine(changeCount);    // Outputs "3"
}
}

对于要求控制事件的底层存储的高级情形,事件声明可以显式提供 add 和 remove 访问器,它们在某种程度上类似于属性的 set 访问器。

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值