接口不包含任何代码或数据:它只规定了从接口继承的类必须提供哪些方法和属性。使用接口,方法的名称/签名可以和方法的具体实现完全隔绝。
抽象类在许多方面都和接口相似,只是它们可以包含代码和数据。然而,可以将抽象类的某些方法指定为虚方法,指示从抽象类继承的类必须以自己的方式实现这些方法。
理解接口
接口指定“有什么”,也就是方法的名称、返回类型和参数。至于具体“如何做”。或者说方法具体如何实现,则不是接口所关心的。接口描述了类提供的功能,但不描述功能如何实现。
定义接口
定义接口类似于定义类,只是要用interface关键字而不是class关键字。在接口中,要按照与类或结构中一样的方式声明方法,只是不允许指定任何访问类型。另外,接口中的方法是没有实现的,它们只是声明。实现接口的所有类型都必须提供自己的实现。所有,方法主体被替换成一个分号。如:
interface IComparable{
int CompareTo(Object obj);
}
Microsoft.NET Framework 文档建议接口名以大写字母I开头。
接口不包含任何数据:不可以向接口添加字段(私有的也不行)。
实现接口
为了实现接口,需要声明类或结构从接口继承,并实现接口指定的全部方法。虽然不能从一个结构派生出另一个结构,但结构是可以实现接口的(从接口“继承”)。
interface ILandBound
{
int NumberLegs();
}
calss Horse: ILandBound
{
..........
public int NumberLegs() //隐式实现接口
{
return 4;
}
}
实现接口时,必须保证每个方法都完全匹配对应的接口方法,具体遵循以下几个规则:
①方法名和返回类型完全匹配
②所有参数(包括ref和out关键字修饰符)都完全匹配
③用于实现接口的所有方法都必须具有public可访问性。但是,如果使用显示接口实现,则不应该为方法添加访问修饰符。
一个类可以在扩展另一个类的同时实现接口。C#用一种位置记号来加以区分。首先写基类名,再写逗号,最后写接口名。如
interface ILandBound
{
............
}
class Mammal
{
.................
}
class Horse:Mammal, ILandBound
{
.................
}
一个接口可以从另一个接口继承,这在技术上称为接口扩展。
使用多个接口
一个类最多只能有一个基类,但可以实现不限数量的接口。
class Horse:Mammal, ILandBound,IGrazable
{
.....................
}
显示实现接口
interface ILandBound
{
int NumberOfLegs(); //几条腿
}
interface IJourney
{
int NumberOfLegs();//跑了几站
}
class Horse : ILandBound, IJourney
{
.......
int ILandBound. NumberOfLegs()
{
return 4;
}
int IJourney. NumberOfLegs()
{
return 3;
}
}
如果方法是显示接口实现的一部分,就不能为方法指定访问修饰符。
访问显示实现接口的方法,通过接口引用对象:
Horse horse = new Horse();
.......
IJourney journeyHorse = horse;
int legInJourney = journeyHorse .NumberOfLegs();
ILandBound landBoundHorse = horse;
int legInHorse = landBoundHorse .NumberOfLegs();
接口的限制
①不允许在接口中定义任何字段,包括静态字段。
②不允许在接口中定义任何构造器。
③不允许在接口中定义任何析构器。析构器包含由于析构(销毁)对象实例的语句。
④不允许为任何方法指定访问修饰符
⑤不允许在接口中嵌套任何类型(如枚举、结构、类或接口)。
⑥虽然一个接口能从另一个接口继承,但不允许从结构或者类中继承一个接口。
抽象类
为了明确声明不允许创建某个类的实例,必须将那个类显式声明为抽象类(不能封装,不允许实例化对象),这是用abstract关键字完成的。如:定义一个草食性哺乳动物抽象类
abstract class GrazingMammal: Mammal,IGrazable
{
........................
}
试图实例化一个GrazingMammal对象,代码将无法通过编译。
抽象方法
抽象类可以包含抽象方法。抽象方法原则上与虚方法相似,只是它不包含方法主体。派生类必须重写(override)这种方法。抽象方法适合在以下情形下使用:一个方法在抽象类中提供默认实现没有意义,但又需要继承类提供该方法的实现。
abstract abstract class GrazingMammal: Mammal,IGrazable
{
abstract void DigestGrass(); //抽象方法
........................
}
密封类
如果不想一个类作为基类使用,可以使用C#提供的sealed(密封)关键字防止类被用作基类。例如:
sealed class Horse: GrazingMammal,ILandBound
{
..................
}
在密封类中不能声明任何虚方法,另外抽象类不能密封。
结构隐式密封。永远不能从一个结构派生。
密封方法
可用sealed关键字密封继承到的虚方法,阻止当前类的派生类继续重写该方法。只有重写方法才能密封(用sealed override 来修饰方法)。可像下面这样理解interface、virtual、override和sealed关键字
interface(接口)引入方法名称。
virtual(虚)是方法的第一个实现,可由派生类重写。
override(重写)是派生类重写的实现,是方法的第二个实现。
sealed(密封)是方法的最后一个实现,再下面的派生类不能重写了。