接口与virtual,override,new关键字
一,类继承接口
1,首先我们定义一个简单的ITeacher接口,并定义一个Professor类继承它。
public interface ITeacher
{
void Print();
} public class Professor : ITeacher
{
public void Print()
{
Debug.Write("I'm Professor!");
}
}
然后用接口变量调用如下:
ITeacher teacher = new Professor();
teacher.Print();
输出结果:I'm Professor!
2,将Professor类的Print方法改为Virtual结果会怎么样?
public class Professor : ITeacher
{
public virtual void Print()
{
Debug.Write("I'm Professor!");
}
}
输出结果:I'm Professor!
Virtual的加入,并没有改变接口的行为,但是有了这个关键字,我们可以在子类中重写Professor类的Print方法。
3,定义AssistantProfessor类,继承自Professor类。
public class AssistantProfessor : Professor
{
public override void Print()
{
Debug.Write("I'm AssistantProfessor!");
}
} ITeacher teacher = new AssistantProfessor();
teacher.Print();
结果输出:I'm AssistantProfessor!
注意,Professor继承了ITeacher接口,它的子类AssistantProfessor无需再显示继承这个接口,子类默认也实现了这个接口,如果子类AssistantProfessor类不实现Print方法,接口会调用父类Professor的Print方法。如果子类AssistantProfessor重写override父类Professor的Print方法,接口会调用子类AssistantProfessor的Print方法,这其实是和类的继承调用一致,用多态可以解释这个原理。
4,在子类AssistantProfessor中使用new关键字,结果会如何?
public class AssistantProfessor : Professor
{
public new void Print()
{
Debug.Write("I'm AssistantProfessor!");
}
}
上面的代码编译没有任何问题,子类AssistantProfessor的Print方法加了new关键字,代表隐藏父类的Print方法。
而不是父类的重写,这时就没有多态了,接口会调用父类的Print方法,所以结果输出:I'm Professor!。
5,孙子类的Print方法,接口还能调用吗?
public class Professor : ITeacher
{
public virtual void Print()
{
Debug.Write("I'm Professor!");
}
} public class AssistantProfessor : Professor
{
public override void Print()
{
Debug.Write("I'm AssistantProfessor!");
}
} public class SubAssistantProfessor : AssistantProfessor
{
public override void Print()
{
Debug.Write("I'm SubAssistantProfessor!");
}
} ITeacher teacher = new SubAssistantProfessor();
teacher.Print();
上面的代码,运行结果:I'm SubAssistantProfessor!
这里依然是多态的作用,不知道大家注意到没有,子类AssistantProfessor用了override关键字,孙子类SubAssistantProfessor居然还能用override关键字,不是只有声明为virtual的方法才能override吗?
利用反编译工具,我们可以清晰的看到带有override的方法,被编译后依然是一个虚方法,可以被重写。我想,
这也是多态的意义所在,后辈子类才能表现出各自不同的行为。
// Methods
.method public hidebysig virtual
instance void Print () cil managed
{
// Method begins at RVA 0x22bb
// Code size 13 (0xd)
.maxstack 8 IL_0000: nop
IL_0001: ldstr "I'm AssistantProfessor!"
IL_0006: call void [System]System.Diagnostics.Debug::Write(string)
IL_000b: nop
IL_000c: ret
} // end of method AssistantProfessor::Print
6,子类显示实现接口
public interface ITeacher
{
void Print();
} public class Professor : ITeacher
{
public virtual void Print()
{
Debug.Write("I'm Professor!");
}
} public class AssistantProfessor : Professor, ITeacher
{
public new void Print()
{
Debug.Write("I'm AssistantProfessor!");
}
} ITeacher teacher = new AssistantProfessor();
teacher.Print();
上面这个例子和上面的情况4只有一点区别,子类AssistantProfessor显示实现了ITeacher接口。这时,通过ITeacher变量直接找到的是子类AssistantProfessor的Print方法,所以输出结果是:I'm AssistantProfessor!
再看看这段代码:
public interface ITeacher
{
void Print();
} public class Professor : ITeacher
{
public virtual void Print()
{
Debug.Write("I'm Professor!");
}
} public class AssistantProfessor : Professor, ITeacher
{
}
上面这段代码结果:I'm Professor!
虽然子类定义了Iteacher接口,但是没有提供任何实现。
再来看看这段代码:
public interface ITeacher
{
void Print();
} public class Professor
{
public virtual void Print()
{
Debug.Write("I'm Professor!");
}
} public class AssistantProfessor : Professor, ITeacher
{
}
这段代码能编译过吗?父类没有实现ITeacher接口,子类实现了Iteacher接口,但却没提供实现方法。
奇怪的是,它能编译通过,运行结果为:I'm Professor!没错!父类实现了ITeacher中定义的方法,子类可以不实现。
上面的一些例子可能有些出乎我们的意料,从中我们也可以大致归纳出接口的调用顺序,去解释那些奇怪的问题。
7,从上面的实验,简单归纳,接口方法执行时的查找顺序:
1) 实例类如果直接继承了接口,则查找实例类上有无接口方法,如果有,直接执行;如果没有,查找实例类父类中有无接口方法,如果有,执行之。(不可能出现找不到的情况,不然编译是通不过的)
2) 实例类如果没有直接继承接口,首先查找实现接口的父类,然后查找父类中有无接口方法,如果有,查看方法是否是virtual方法,如果是,查看实例类有无重写这个方法,如果重写则调用实例类的方法,如果没有重写,直接调用父类的virtual方法。如果在实现接口的父类中没有找到接口方法,则在父类的父类往上查找,直到找到为止,执行该方法。(同理,也不可能出现找不到的情况,不然编译通不过)
二,接口间的继承
1,接口可以继承接口
public interface ITeacher
{
void Print();
} public interface IGoodTeacher : ITeacher
{
void Read();
}
如果我们要定义一个类来继承IGoodTeacher的话,必须同时实现Print和Read方法,不然会编译出错
public class Professor : IGoodTeacher
{
public void Print()
{
Debug.Write("I'm Professor! Print");
} public void Read()
{
Debug.Write("I'm Professor! Read");
}
}
2,子类如果继承Professor,也会自动继承IGoodTeacher
public class AssistantProfessor : Professor
{
}
AssistantProfessor没有提供任何方法,即便AssistantProfessor在显示继承IGoodTeacher接口,也可以不提供任何方法,因为它的父类已经提供了这些方法,这和我们上面讨论的类继承接口的分析方法是一致的,这里就不做进一步的讨论了。
接口与virtual,override,new关键字的更多相关文章
- C# virtual,override,new 整理
今天仔细学习了一下C#中virtual, override, new关键字,参考了网上的很多资料,现整理一下. Virtual: virtual 关键字用于修饰方法.属性.索引器或事件声明,并使它们可 ...
- C# virtual override 和 new 的区别
一直以来我都对 virtual override 和 new 之间的区别感到疑惑不解. 特别笔试的时候特别容易考到,真的很容易弄错啊,畜生! 光看理论永远记不住,那不如写几行代码就懂了. 首先看看v ...
- RobotFramework下的http接口自动化Get Response header 关键字的使用
Get Response header 关键字用来获取http请求返回的http响应头部数据. 常见的Response Header: Header 解释 示例 Accept-Ranges 表明服务器 ...
- RobotFramework下的http接口自动化Get Response Body关键字的使用
Get Response Body 关键字在上面已经有用到了,服务器端在处理完成了发出的http请求后,会给出对应的响应结果,那么Get Response Body这个关键字就是来获取响应结果中的主体 ...
- C#关于private protected sealed Virtual/Override
Public:公开权限 Private:修饰类时类为程序集或者包含此类的类内部权限:修饰变量时只能类内部使用: Protected:修饰变量,只能继承类可以使用,对外(包括继承类的实例)无权限: Ab ...
- Abstract和Virtual和interface , 派生类中重写 override / new关键字
http://www.cnblogs.com/blsong/archive/2010/08/12/1798064.html C#中Abstract和Virtual 在C#的学习中,容易混淆virtua ...
- Modifiers: virtual, override, new, abstract, sealed, internal
internal 声明类.类成员.接口或接口成员具有内部可见性. internal 修饰符使类.接口或成员仅在当前包中可见. 当前包之外的代码不能访问 internal 成员.只有在同一程序集的文件中 ...
- 不要在对抽象类接口abstract virtual什么的混淆不清了
(最近带一个新手入门 讲这边老费力了.) 接口和抽象类不过都是类的抽象罢了,这是他们的本质,只不过人们的思维角度不同而已,一个偏向为行为契约上的抽象(接口) 一个更像大自然中的繁衍关系(抽象类). 直 ...
- C# abstract virtual override new finally java final finalize
virtual:声明虚方法.可以被其派生类所重写的.重写方法需要使用override或者new关键字. override:覆盖原方法.可对重写virtual.override.abstract进行重写 ...
随机推荐
- Android通讯录管理(获取联系人、通话记录、短信消息)
前言:前阵子主要是记录了如何对联系人的一些操作,比如搜索,全选.反选和删除等在实际开发中可能需要实现的功能,本篇博客是小巫从一个别人开源的一个项目抽取出来的部分内容,把它给简化出来,可以让需要的朋友清 ...
- [转]Maven - 环境配置
Maven 是一个基于 Java 的工具,所以要做的第一件事情就是安装 JDK. 系统要求 项目 要求 JDK Maven 3.3 要求 JDK 1.7 或以上Maven 3.2 要求 JDK 1.6 ...
- PHP百分号转小数,php 小数转换百分数函数
PHP百分号转小数: <?php $a = "20.544545%"; echo (float)$a/100; ?> php 小数转换百分数函数: function x ...
- 增加nginx虚拟主机配置文件(conf.d)
有时候我们按照了nginx后发现配置文件只有一个,/etc/nginx/nginx.conf 所有的配置包括虚拟目录也在此文件中配置, 这样当虚拟主机多了管理就有些不方便了, 这是需要我们把配置文件拆 ...
- 由初始化线程池引发的NoClassDefFoundError 异常分析
今天说的异常是一个很不常见的异常,至少我不经常见到这个异常.首先先看下NoClassDefFoundError官方定义 : Java Virtual Machine is not able to fi ...
- iOS 在object-c 中调用c文件 方法
1,新建c 头文件 lib.h 定义 c 函数 2,新建 c 实现文件,新建模板选中 c File lib.c 3,oc 中调用,引用 c 头文件 lib.h ok .搞定
- destoon入门实例与常见问题
收集了一些destoon入门实例与常见问题,大家做个参考. 链接如下: destoon忘记后台密码怎么办?destoon找回管理员密码 忘记destoon管理员后台账号密码怎么办?解决方法 desto ...
- ios 关于屏幕旋转和屏幕晃动
内置加速计是智能手机最酷的特性之一,ios可以通过这个小设备知道用户握持手机的方式,以及用户是否移动了手机,ios使用加速计处理自动旋转,并且许多游戏都是用它作为控制机制,它还可以用于检测摇动和其他突 ...
- Nginx配置优化参考
Nginx配置优化参考 ...
- [Windows Azure] What is a cloud service?
What is a cloud service? When you create an application and run it in Windows Azure, the code and co ...