类是面向对象语言的一个基本特征,是一种复杂的数据类型。
C#中定义类只需使用class关键字并按格式定义即可,方法为:
class Person
{
//类成员定义
}
若class关键字前没有显式的指定访问修饰符,则类的访问修饰符为internal,也可以指定private、protected、public、abstract、和sealed等修饰符,以及这几个修饰符的组合:
修饰符 | 访问权限 |
---|---|
无或internal | 只能在同一程序集中访问类 |
public | 同一程序集或引用该程序集的其他程序集都可以访问类 |
abstract或internal abstract | 只能在同一程序集中访问类,该类不能被实例化,只能被继承 |
public abstract | 同一程序集或引用该程序集的其他程序集都可以访问类,不能被实例化,只能被继承 |
sealed或internal sealed | 只能在同一程序集中访问类,该类不能被继承,只能被实例化 |
public sealed | 同一程序集或引用该程序集的其他程序集都可以访问类,不能被继承,只能被实例化 |
资料:C#之继承
类成员定义包括:字段、属性、方法、构造函数、析构函数和索引器等。它们也都有自己的访问权限,也可以指定public、private、internal和protected等修饰符,也可是使用static关键字将其声明为类的静态成员。静态成员属于类级别的概念,不属于类的实例(类的实例也叫做类的对象)。
使用不同的修饰符导致类的成员具有不同访问权限:
修饰符 | 访问权限 |
---|---|
public | 同一程序集或引用该程序集的其他程序集都可以访问 |
private | 只有同一个类中可以访问 |
protected | 只有同一个类或派生类中可以访问 |
internal | 只有同一程序集中可以访问 |
protected internal | 在同一个程序集、该类和派生类中可以访问 |
字段的定义由访问修饰符、字段的类型和字段名称组成,定义方法为:
pubilc class Person
//定义了类Person
{
//定义字段:姓名、年龄、性别
private string name;
public int age;
protected bool sex;
}
还可以用关键字readonly或const来定义字段,但使用readonly表示字段是只读的,且不需要在定义时初始化,使用const表示该字段是不变的,且必须在定义时初始化。
也可以使用static关键字来声明静态字段,区别在于静态字段必须通过类来访问,而实例字段则需要通过类的对象实例来进行访问。静态字段定义方法:
public class Person
{
//静态字段定义
pubilc static string name;
//实例字段定义
public int age;
}
以上代码中定义的静态字段name只能通过类名,即Person.name的方式来访问;而对于实例字段age,则不能这样访问,应通过类的实例对象,即new Person().age的方式来访问(new Person()表示实例化一个Person对象)。
属性是对字段的拓展。当字段为私有字段时(private),为了访问该私有字段,用属性来对字段进行控制和访问。属性定义主要由get访问器和set访问器组成,get访问器负责对字段内进行读取,set访问器负责为字段进行赋值。属性的定义方法为:
public class Person
{
//私有字段定义
private string name;
//公有属性定义
pubilc string Name //属性的类型(string)必须和字段的类型(string)一致
{
//get访问器
get
{return name;}
//set访问器
{
name = value;
//value是隐式参数
}
}
}
当属性仅包含get访问器,或set访问器为private级别时,这样的属性被称为只读属性;当属性仅包含set访问器,或get访问器为private级别时,这样的属性被称为只写属性。
属性也可通过static关键字来声明为静态属性,此时静态属性属于类级别,不能通过类的实例进行访问,也不同在静态属性中使用非静态的字段。静态属性的定义为:
public class Person
{
//静态字段定义
public static string name;
//静态属性
public static string Name
{
get{return name;}
set{name = value;}
}
}
方法由方法签名和代码块组成。方法签名包括方法的访问级别(如public、private)、可修饰符(如abstract关键字)、方法名称和参数。main也是一个方法,且时每个程序的入口。方法的定义为:
public class Person
{
//定义一个没有返回值的打印方法,name是用户传入的参数
public void Print(string name)
{
Console.WriteLine("输入的值为:" + name);
}
}
要调用定义好的方法,则可以使用方法名称,并传入方法的参数个数和对应类型来对方法进行调用,例如:
class Program
{
//在Main方法中调用Person类中的Print方法
static void Main(string[] args)
{
//初始化类的实例
Person P = new Person();
//通过使用方法名称,并传入对应的参数个数和类型来对方法进行调用
P.Print("张三");
}
}
方法也可以用static关键字声明为静态方法。此时静态方法属于类级别,不能通过类的实例进行访问。静态方法的定义为:
public class Person
{
public static void Print(string name)
{
Console.WriteLine("输入的值为:" + name);
}
}
静态方法的调用不能通过类的实例进行访问,需直接通过类进行调用,例如在Main中调用上面静态方法:
class Program
{
static void Main(string[] args)
{
Person.Print("张三");
}
}
资料1:关于c#静态方法和实例方法的辨析和应用
资料2:
C#的类中可以包含两种方法:静态方法和非静态方法。
使用了static 修饰符的方法为静态静态方法,静态方法。
静态方法是一种特殊的成员方法,它不属于类的某一个具体的实例,而是属于类本身。
所以静态方法不需要 首先创建一个类的实例,而是法的格式 。
1.static方法是类中的一个成员方法,属于整个类,即不用创建任何对象也可以直接调用!static内部只能出现static变量和其他static方法!而且static方法中还不能使用this….等关键字..因为它是 属于整个类!
2.静态方法效率上要比实例化高,静态方法的缺点是不自动进行销毁以做销毁。
3.静态方法和静态变量创建后始终使用同一块内存,而使用实例的方式会创建多个内存。
4.C#中的方法有两种:实例方法,静态方法. 类的方法代码只有一份,它们的生命周期和类是一致的.实例方法是通过对象名调用的,静态方法与类关联而不是 与对象名关联。
5.那么在程序中什么地方可以利用静态字段和静态构造方法,通常适用于于一些不会经常变化而又频繁使用的数 据,比如连接字符串,配置信息等,当满足上面所 说的两点时,进行一次读取,以后就可以方便的使用了,同 时也节约了托管资源,因为对于静态成员,一个静态字段只标识一个存储位置。
方法重载:C#中支持方法重载
方法重载指的是在类中可以定义多个名称相同但方法签名不同的方法。“方法签名不同”指的是方法的参数顺序、参数类型和个数不同(需要注意的是,方法返回类型不属于方法签名的一部分)。
构造函数主要用于创建类的实例对象。当调用构造函数创建一个对象时,构造函数会为对象分配内存空间,并初始化类的成员。构造函数分为实例构造函数和静态构造函数。
实例构造函数用于创建和初始化类的实例。定义方法为:
public class Person
{
private string name;
//无参数的实例构造函数
public Person()
{
name = "张三";
}
//有参数的实例构造函数
public Person(string name)
{
//使用this关键字来引用字段name,与参数name区分开来
this.name = name; //this代表当前类的实例对象
}
}
实例构造函数必须满足:构造函数必须和类同名;构造函数不允许有返回类型(如string)。从上面代码可以看出,实例构造函数也支持方法重载。
以上代码使用了public关键字修饰构造函数,被称为公共构造函数。当使用private关键字修饰时称为私有构造函数。如果类只定义了一个或多个私有构造函数,则其他类不能通过调用该类的私有构造函数来创建类的实例。私有构造函数最典型的应用时设计模式中单例模式的实现,例如:
class Person
{
private string name; //私有字段定义
public static Person person; //公有静态字段定义
//公有属性定义
public string Name
{
get{return this.name;}
}
//定义私有构造函数,只能在类内部调用,即类的实例化只能在类定义时被实例化
private Person()
{
Console.WriteLine("私有构造函数被调用");
this.name = "张三";
}
//定义静态方法,用于返回类的实例
public static Person GetInstance()
{
person = new Person();
return person;
}
}
class Program
{
static void Main(string[] args)
{
//通过调用GetInstance()静态方法来返回一个Person实例,此时不能使用new运算符来创建实例,即不能使用Person person = new Person()来创建实例
Person person = GetInstance();
Console.WriteLine("类实例的Name属性为:{0}", person.Name);
Console.Read();
}
}
运行以上程序,结果为:
私有构造函数被调用
类实例的Name属性为:张三
静态构造函数用于初始化类中的静态成员。静态构造函数的使用方法:
class Person
{
private static string name;
//定义静态构造函数,仅执行一次
static Person()
{
Console.WriteLine("静态构造函数被调用了");
name = "张三";
}
public static string Name
{
get{return name;}
}
}
class program
{
static void Main(string[] args)
{
Console.WriteLine(Person.Name);
Console.WriteLine(Person.Name);
Console.Read();
}
}
运行以上程序,结果为:
静态构造函数被调用了
张三
张三
由此可见,虽然调用了两次Person对象的静态Name属性,但输出了一次“静态构造函数被调用了”,说明静态构造函数只能执行一次。此外,静态构造函数与实例构造函数一样不能直接调用,在私有构造函数示例中,通过调用静态方法来返回构造函数中类的实例的,而在上面静态构造函数的示例中是通过调用公有静态属性,通过get访问器来返回构造函数中类的实例的。另外,在程序中,无法控制执行静态构造函数的时机。
析构函数(即Finalize方法)用于在类销毁之前释放类实例所使用的托管和非托管资源。
资料:#中的托管与非托管资源
析构函数的定义为:
class Person
{
~Person()
{
Console.WriteLine("析构函数被调用了");
}
}
析构函数只能对类使用,不能对结构体使用,且一个类只能有一个析构函数。并且若在一个类中定义了析构函数,则不需也无法显式地调用析构函数(如在Main中无需调用~class()去释放非托管资源,类会自动的执行该~class()函数释放内存空间)。
索引器可以简化对类中数组成员的访问。索引器的定义为:
[修饰符] 数据类型 this index]
{
get{ //返回类中数组的某个元素}
set{ //对类中数组元素赋值}
}
索引器的定义过程和使用如下:
class Person
{
//定义一个可容纳10个整数的私有整数数组
private int[] intArray = new int[10];
//索引器定义
public int this[int index]
{
get
{
return intArray[index];
}
set
{
intArray[index] = value;
}
}
}
class Program
{
static void Main(string[] args)
{
Person person = new Person();
int i = 0;
//通过索引器对类中的数组进行复制
person[0] = 1;
person[1] = 2;
person[2] = 3;
//输出数组的值
while(i<10)
{
Console.Write(person[i] + " ");
i++;
}
Console.Read();
}
}
运行以上程序,结果为:
1 2 3 0 0 0 0 0 0 0
从以上代码可以看出,索引器也是一种针对私有字段进行访问的方式,但此时的私有字段是数组类型,而属性则一般只对简单数据类型的私有字段进行访问。
类的成员定义包括字段、属性、构造函数、方法、析构函数和索引器等,但要访问这些实例成员,必须通过类的实例对象来完成。而要得到一个类的实例对象,就必须先声明一个该类类型的变量,然后使用new运算符后跟类的实例构造函数来完成实例化。实例方法为:
class Person
{
//定义字段:姓名、性别
private string name;
public bool sex;
//公有属性定义
public string Name
{
get;
set;
}
public bool Sex
{
get;
set;
}
//定义带两个参数的实例构造函数
public Person(string name, bool sex)
{
this.name = name;
this.sex = sex;
}
}
class Program
{
static void Main(string[] args)
{
//实例化两个类的对象
Person person1 = new Person("张三", ture);
Person person2 = new Person("李四", false);
}
}
只有包含实例构造函数的类才能被实例化,而在静态类中使不能定义实例构造函数的,也无法被实例化。
①类使用关键字class,结构体使用关键字struct;
②结构体中不可对声明字段进行初始化,但类可以。如:
struct Point
{
private int x =1;
int y = 2;
}
则会出现错误:“结构体与类区别.Point.x”:结构中不能有实例字段初始值
③类中若没有显式的定义构造函数,则编译器会自动生成一个无参数的实例构造函数(隐式构造函数),而若显式的定义了一个构造函数,编译器就不再生成隐式构造函数;
结构体中,无论是否显式的定义了构造函数,隐式构造函数都一直存在。
④结构体中不能显式的定义一个无参数的构造函数,而类中可以。
⑤在结构体的构造函数中,必须要为结构体中的所有字段赋值。如:
struct Point
{
private int x;
private int y;
public Point(int x)
{
this.x = x;
}
}
则会出现错误:控制返回调用方之前,字段“结构体与类区别.Point.y”必须被完全赋值
⑥创建结构体对象可以不适用new关键字,但姿势结构体对象中的字段没有初始值;而类必须使用new关键字来创建对象。
⑦结构体不能继承结构或类,但可以实现接口;而类可以继承类,但不能继承结构,也可以实现接口。
⑧类是引用类型,而结构体是值类型。
⑨结构体不能定义析构函数,而类可以。
⑩不能用abstract和sealed关键字修饰结构体,而类可以。