c#:浅析接口(interface)与抽象类(abstract)的区别
在学习c#接口(interface)和抽象类(abstract)的时候 发现接口和抽象类极为相似,比如说:继承后都需要重写,或者都不能通过new关键字来实例化… ,那么他们之间到底有什么区别与联系 ?一、接口的特征 1、接口使用interface关键字声明 2、接口中的成员有属性、方法、事件,索引器并且都没有实现部分,可以说是没有方法体 3、接口中不能声明字段,接口中的成员不能使用任何修饰符
【虚方法】
virtual关键字用于在基类中修饰方法(或属性、索引器或事件声明),并且允许在派生类中重写这些对象(即override可写可不写)。
virtual的使用会有两种情况:
情况1:在基类中virtual方法在子类中没用override重写。那么在对子类实例的调用中,该虚方法使用的是基类定义的方法。
情况2:在基类中virtual方法在派生类中使用override重写。那么在对子类实例的调用中,该虚方法使用的是子类重写的方法。
【抽象方法】
abstract关键字只能用在抽象类中修饰方法,并且没有具体的实现(没有方法体),抽象方法必须放在抽象类中(但抽象类中可以没有抽象方法)。
非抽象类的派生类必须全部实现父类的抽象方法和抽象访问器,使用override关键字来实现。
【接口】
接口用于描述一组类的公共方法/公共属性
接口中的方法没有具体实现,也就是没有方法体,必须由继承者去实现而且必须全部实现。
接口中的方法不需要修饰符,默认就是公有的(Default / Public)
接口可以包含方法、属性、索引器、事件。不能包含任何其他的成员,例如:常量、字段、域、构造函数、析构函数、静态成员
【虚方法 VS 抽象方法】
虚方法和抽象方法都可以供派生类重写
1. 虚方法必须有实现部分,抽象方法没有提供实现部分,抽象方法是一种强制派生类覆盖的方法,否则派生类将不能被实例化;而虚方法提供了选择,可以覆盖可以不覆盖。
2. 抽象方法只能在抽象类中声明,虚方法不是。
【抽象 VS 接口】
抽象类和接口都不能实例化(无法New创建实例,只能被继承)
抽象类可以包含非抽象方法,而接口只能包含抽象方法
一个类可以实现多接口,单继承。(可以继承多个接口,但只能继承单个类)
在学习c#接口(interface)和抽象类(abstract)的时候 发现接口和抽象类极为相似,比如说:继承后都需要重写,或者都不能通过new关键字来实例化… ,那么他们之间到底有什么区别与联系 ?
一、接口的特征
1、接口使用interface关键字声明
2、接口中的成员有属性、方法、事件,索引器并且都没有实现部分,可以说是没有方法体
3、接口中不能声明字段和常量,接口中的成员不能使用任何修饰符
4、继承接口的类或结构必须隐式或显式实现接口中的所有成员
5、一个接口允许继承多个接口,一个类也可以继承多个接口,但是只能继承一个基类。
C#不允许多重类继承(子类继承多个父类),但允许多重接口实现(子类继承多个父接口)。
6、接口不能通过new关键字来实例化
7、类或结构继承接口或不用使用override关键字即可实现
8、接口中没有实例构造函数
1 public interface IPict{
2 void DisplayImage();
3 }
4
5 public interface IPictManip{
6 void DisplayImage();
7 }
8
9 public class MyImages: IPict, IPictManip{
10 void IPict.DisplayImage(){ //如果用显式接口实现方法,则不需使用访问修饰符
11 Console.WriteLine("DisplayImage的IPict实现");
12 }
13 void IPictManip.DisplayImage(){
14 Console.WriteLine("DisplayImage的IPictManip实现");
15 }
16 }
17
18 static void Main(string[] args){
19 MyImages objM = new MyImages();
20 IPict Pict = objM; //IPict引用
21 Pict.DisplayImage();
22 IPictManip PictManip = objM; //IPictManip引用
23 PictManip.DisplayImage();
24 }
二、抽象类的特征
1、抽象类中允许有实例方法,也就是说抽象类中除了抽象方法以外,其他的成员允许有具体的实现
2、抽象类中的抽象方法没有实现部分,也就是说没有方法体,并且继承此抽象类的非抽象类必须使用override关键字来重写抽象类中的所有方法
3、在抽象类中可以声明任何类成员,并且类成员可以使用任意的修饰符 (接口不行)
4、抽象类仅能让非抽象类和抽象类继承
5、非抽象类继承抽象类后必须重写(实现)抽象类中的所有抽象方法,抽象类继承抽象类后可以只实现部分抽象方法
三、总结
1、接口与抽象类的相同点
(1)都不能使用new关键字来实例化
(2)成员方法都没有实现部分,或者说都没有方法体
(3)继承他们的,都必须实现他们的成员方法
2、接口和抽象类的不同点
接口(interface) | 抽象类(abstract) |
---|---|
接口中不能声明字段和常量,接口成员有:属性、方法、事件、索引器 | 抽象类中可以声明任何类成员 |
在接口中只能定义成员,但不能具体实现。(没有方法体) | 在抽象类中除了抽象方法以外,其他成员允许有具体的实现 |
接口中没有实例构造函数,也就是说没有构造函数 | 抽象类中有构造函数 |
接口成员不能使用任何访问修饰符 | 抽象类中的类成员可以使用任意的访问修饰符 |
继承接口的类或结构必须隐式或显式实现接口中的所有成员,否则需要将实现类定义为抽象类,并将接口中未实现的成员以抽象的方式实现 | 继承抽象类的类必须重写实现抽象类中的所有抽象方法,或者抽象类继承抽象类,可以重写部分抽象方法 |
接口不能作为派生类继承 | 抽象类可以继承非抽象类或抽象类 |
接口可以作为基类来多继承:接口、类和结构 | 抽象类可以作为基类只能实现单继承,只能让非抽象类或者抽象类继承 |
抽象类(abstract)和接口(interface)的实现
抽象类
抽象方法是没有代码实现的方法,使用abstract关键字修饰;
- 抽象类是包含0到多个抽象方法的类,其不能实例化。含有抽象方法的类必须是抽象类,抽象类中也可以包含非抽象方法;
- 重写抽象类的方法用override关键字。
1 //定义一个抽象类,包含一个抽象方法,但该方法未实现
2 abstract class MyAbs{
3 public abstract void AbMethod();
4 }
5 //定义一个非抽象派生类,只能继承一个类
6 class MyClass:MyAbs{
7 public override void AbMethod(){
8 Console.WriteLine("此MyClass中实现父类中未实现的抽象方法!");
9 }
10 }
11 //在主程序中实例化一个MyClass对象,并调用AbMethod方法
12 static void Main(string[] args){
13 MyClass objMyClass = new MyClass();
14 objMyClass.AbMethod();
15 }
- 虚方法(virtual)与抽象方法(abstract)的区别
- 虚方法必须要有方法体(方法体可以没有内容,但必须保留大括号),抽象方法不允许有方法体(不能有大括号);
父类的虚方法:
protected virtual void Initialization()
{
}
子类的方法重写:
protected override void Initialization()
{
MsgTypeName = NAME;
LoadChildrenUIFormList = new List<string> { "TrainingGround_SkillInfoBoxUI" };
CurrentUIType.UIForms_ShowMode = UIFormShowMode.HideOther;
}
2. 虚方法可以被子类重载(override)(也可以不重载,在对子类实例的调用中,该虚方法使用的是基类定义的方法),抽象方法必须被子类重载(必须重新继承实现);
3.虚方法除了在 (sealed) 密封类中都可以写,抽象方法只能在抽象类中写(抽象类中不是必须要有抽象方法,抽象方法可以为0个)。
接口
接口是一套规范,遵守这个规范就可以实现功能。
- 接口中只定义方法的原型,不能有字段和常量;
- 继承接口的类 必须实现接口中所有的方法 才能实例化
1 //隐式声明为public
2 public interface IPict{
3 //只有方法声明,没有访问修饰符,没有实现
4 int DeleteImage();
5 void DisplayImage();
6 }
定义派生自接口的类,并实现所有接口中的方法
1 public class MyImages: IPict{
2 //第一个方法的实现
3 public int DeleteImage(){
4 Console.WriteLine("DeleteImage实现!");
5 }
6
7 //第二个方法的实现
8 public void DisplayImage(){
9 Console.WriteLine("DisplayImage实现!");
10 }
11 }
在主程序中实例化一个MyImages对象,并调用DeleteImage和DisplayImage方法
1 static void Main(string[] args){
2 MyImages ofjM = new MyImages();
3 objM.DisplayImage();
4 int t = objM.DeleteImage();
5 Console.WriteLine(t);
6 }
- 多重接口实现
C#不允许多重类继承(子类继承多个父类),但允许多重接口实现(子类继承多个父接口)。但如果发生命名冲突就需要使用前缀进行显式接口实现或调用。如果继承接口的类中用显示方法实现接口中的方法时,实现方法不需加访问修饰符(public)
1 public interface IPict{
2 void DisplayImage();
3 }
4
5 public interface IPictManip{
6 void DisplayImage();
7 }
8
9 public class MyImages: IPict, IPictManip{
10 void IPict.DisplayImage(){ //如果用显式接口实现方法,则不需使用访问修饰符
11 Console.WriteLine("DisplayImage的IPict实现");
12 }
13 void IPictManip.DisplayImage(){
14 Console.WriteLine("DisplayImage的IPictManip实现");
15 }
16 }
17
18 static void Main(string[] args){
19 MyImages objM = new MyImages();
20 IPict Pict = objM; //IPict引用
21 Pict.DisplayImage();
22 IPictManip PictManip = objM; //IPictManip引用
23 PictManip.DisplayImage();
24 }
- 使用自定义接口
接口作为参数使用:接口作为参数传递了实现接口的对象
1 //无论谁收作业参数类型部分都不需做任何改变
2 private void DoCollectHomework(IHomeworkCollector collector){
3 collector.CollectHomework();
4 }
5
6 DoCollectHomework(scofield);
接口作为返回值使用:接口作为返回值返回了一个实现接口的对象
1 private IHomeworkColletor CreateHomeworkCollector(string type){
2 switch(type){
3 case "student":
4 collector = new Student("Scofield", Genders.Male, 28, "越狱");
5 break;
6 }
7 //返回一个实现该接口的对象
8 return collector
9 }
10
11 collector.CollectHomework();
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)