接口与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进行重写 ...
随机推荐
- (面试题)synchronized 和 java.util.concurrent.locks.Lock 的异同
主要相同点: Lock 能完成 synchronized 所实现的所有功能: 主要不同点: Lock 有比 synchronized 更精确的线程语义和更好的性能. synchronized 会自动释 ...
- 重新认识Javascript的一些误区总结
1.在函数内有没有var真的不一样 下面这样一段代码,在函数abc()中,创建了两个变量a, c,并在函数体之外进行alert,想看看有什么事发生: <script> function a ...
- UI测试后生成测试报告,利用shell脚本上传svn
ui测试后生成测试报告,把报告保存在某一个固定路径 shell脚本把这个报告上传 #!/bin/bash -ile #svn下载文件 #svn checkout http://svn.xxx.com/ ...
- navicat cannot create oci 解决
1.新建连接 2.连接时候报错 3.解决 3.1.选择对应版本OCI 3.1.配置OCI[工具->选项...]
- javaweb下载文件
//读取文件->写出文件 public static void main(String[] args) { InputStream in =null; OutputStream out = nu ...
- 关于 隐藏元素(样式为 display: none 的元素)及其子元素 获取不到高度的问题
IE 和 Edge 中都是这样,Chrome中好像还好. 方法就是换一个样式,还有一个控制显示隐藏的:visibility 相关文档:http://www.w3school.com.cn/cssref ...
- LeetCode Permutaions II
LeetCode解题之Permutaions II 原题 输出一个有反复数字的数组的全排列. 注意点: 反复数字的可能导致反复的排列 样例: 输入: nums = [1, 2, 1] 输出: [[1, ...
- Android:UI 沉浸式体验,适合第一屏的引导图片、预览图片。
链接:http://www.cnblogs.com/liushilin/p/5799381.html
- FlexPaper:使用flash在线展示pdf
WFTools工具包中的PDF2SWF工具可用来将PDF格式文件转换成SWF格式.使用下面的命令可以将pdf文件转换为单页swf文件. pdf2swf pdfPath –o swfPath –T ...
- js包管理工具-- yarn
yarn对比npm的优点 根据官方文档yarn具有6大优点 离线模式 yarn会有一个缓存目录,会缓存以前安装过的软件包,再次安装时就不必从网络下载了,大大加速安装速度. 这一点很重要,npm 饱受诟 ...