接口与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进行重写 ...
随机推荐
- JAVA中使用HTTP 1.1提高基于AXIS 1.4的web service的性能
HTTP 1.1会在第一次连接的时候进行认证, 而在一定时间内保持连接而不用重新验证. 一般情形下,每个web service请求都会在web service服务端验证, 而验证会消耗很多时间, 因此 ...
- MapReduce中,new Text()引发的写入HDFS的输出文件多一列的问题
前段时间业务系统有个模块数据没有了,在排查问题的时候发现中间处理环节出错了,错误日志为文件格式不正确,将数据导出后发现这个处理逻辑的输入文件中每一行都多了一列,而且是一个空列(列分隔符是\t).第一次 ...
- Mysql show processlist 排查问题
一.命令概述: mysql show full processlist 用来查看当前线程处理情况,具体信息请参考官网:https://dev.mysql.com/doc/refman/5.7/en/s ...
- DBUtils查找最大的ID总是返回0
1.实体: public class Order { private int id; private Date orderDate; public int getId() { return id; } ...
- android studio(AS) Duplicate files copied in APK META-INF/NOTICE.txt
File 1: /home/slava/.gradle/caches/modules-2/files-2.1/org.apache.httpcomponents/httpmime/4.3.1/f789 ...
- 腾讯云服务器 离线安装最新稳定版MariaDB 10.2.6
数据库方面我们一般都是使用mysql,由于前段时间我们切换到了MariaDB后,当然生产环境也要更着变,谁叫oracle是个碧池呢! mariaDB主要有三种安装方式 源码安装,有点繁琐,不推荐 yu ...
- C#-微信公众平台接口-上传临时素材
最烦做微信公众平台的东西..文档说得不清不楚,又没示例代码,只能自己 慢慢搜索,弄了一晚上,基本弄出来了,把本地的图片上传到微信的临时素材那里,返回媒体ID,用于其他操作,代码如下 :(自己导入相应的 ...
- Atitit jdbc 处理返回多个结果集
Atitit jdbc 处理返回多个结果集 Statement接口提供了三种执行SQL语句的方法: executeQuery.executeUpdate和execute.使用哪一个方法由SQL语句所 ...
- 5. MIZ7035 PCIe测试 RIFFA【PCIE视频传输】
1.前言 MIZ7035官方提供了两种pcie的demo,一个就是普通的PIO测试,一个是BMD测试.我只是试验了PIO功能,可以对板卡直接进行IO寄存器读写.而另外一个BMD功能使用了DMA来加速数 ...
- [nginx]location语法
location语法 location语法格式 location [=|~|~*|^~] uri { .... } location [=|~|~*|^~] uri {....} 指令 匹配标识 匹配 ...